简体   繁体   English

C ++破坏了我的想法,如何信任自动垃圾收集器?

[英]C++ corrupt my thinking, how to trust auto garbage collector?

I use to program mainly with C/C++, that's make me dealing with pointers and memory management daily. 我主要使用C / C ++进行编程,这使我每天处理指针和内存管理。 This days I'm trying to develop using other tools, such as Java, Python and Ruby. 这一天我正在尝试使用其他工具开发,例如Java,Python和Ruby。

The problem is that I keep thinking C++ style, I'm writing code as C++ usually written in almost every programming language, and the biggest problem is the memory management, I keep writing bad code using references in Java and just get as close as I can to the C++ style. 问题是我一直在思考C ++风格,我编写的代码通常是用几乎所有编程语言编写的C ++,而最大的问题是内存管理,我一直在使用Java中的引用编写错误的代码,并且只是像我一样接近可以达到C ++风格。

So I need 2 thinks here, one is to trust the garbage collector, let's say by seeing benchmarks and proofs that it's realy working in Java, and know what I should never do in order to get my code the best way it can be. 所以我需要2想到这里,一个是信任垃圾收集器,让我们说通过看看基准测试和证明它确实在Java中工作,并知道我应该做什么,以便让我的代码最好的方式。

And the second think is knowing how to write other languages code. 第二个想法是知道如何编写其他语言代码。 I mean I know what to do, I'm just never write the code as most Java or Python programmers usually do, are there any books for C++ programmers just to introduce me to the writing conventions? 我的意思是我知道该怎么做,我只是从来没有像大多数Java或Python程序员那样编写代码,是否有任何C ++程序员的书只是为了向我介绍编写约定? (by the way, forgive me for my English mistakes) (顺便说一句,原谅我的英语错误)

Having a good intuition for memory usage and common leaks is a good thing in Java as well. 对于内存使用和常见泄漏具有良好的直觉也是Java中的一件好事。 That memory leaks are impossible in Java is a common misconception . Java中不可能发生内存泄漏是一种常见的误解

Someone who ignores careful memory management, will for instance quickly end up with large trees of dangling GUI components, reachable from listener lists in long lived models. 例如,忽略仔细内存管理的人将很快得到大量悬挂GUI组件的树,可以从长期存在的模型中的侦听器列表中获取。 (Been there, done that.) (去过也做过。)

Keep writing your code structurally, and don't "exploit" the fact that you can be lazy. 继续在结构上编写代码,不要“利用”你可能懒惰的事实。

Another misconception is that the garbage collector is "slow". 另一个误解是垃圾收集器“慢”。 The algorithms are quite efficient and you should not worry about it until you've profiled your program. 这些算法非常有效,在您分析程序之前不必担心它。 A good tool is JVisualVM (bundled with the JDK). 一个好的工具是JVisualVM(与JDK捆绑在一起)。 That tool will show you CPU-profiling and can help you with possible memory leaks and track down unnecessary small temporary allocations. 该工具将向您显示CPU分析,可以帮助您解决可能的内存泄漏并跟踪不必要的小临时分配。

One difference to bear in mind is that in C++ the destructor can be used to clean up any kind of resource, not just memory (ie RAII ). 需要记住的一个区别是,在C ++中,析构函数可用于清理任何类型的资源,而不仅仅是内存(即RAII )。 In Java you have to explicitly close files, sockets, datastore connections etc in a try - finally block. 在Java中,您必须在try-finally块中显式关闭文件,套接字,数据存储区连接等。 If you put resource cleanup code in a Java finalize method then it may get called at some indeterminate time in the future, or never, so is not recommended. 如果将资源清理代码放在Java finalize方法中,那么将来可能会在某个不确定的时间调用它,或者从不调用,因此不建议这样做。 So in some ways this puts a bigger burden on the programmer, not less. 因此,在某些方面,这会给程序员带来更大的负担,而不是更少。

Python is somewhere in between - you can use the 'with' statement to handle automatic cleanup for most resources. Python介于两者之间 - 您可以使用'with'语句来处理大多数资源的自动清理。

The two problems in C++ memory management are memory leaks and trying to use an object that has already been destroyed. C ++内存管理中的两个问题是内存泄漏并试图使用已经被破坏的对象。 As others have pointed out you can also get memory leaks in Java (and Python) if you keep a reference to an object that you no longer need, which in turn may have references to other objects. 正如其他人指出的那样,如果你保留对不再需要的对象的引用,你也可以在Java(和Python)中获得内存泄漏,而这些对象又可能引用其他对象。 Memory leaks in Java may be less frequent but when they do occur they can be much bigger than in C++. Java中的内存泄漏可能不那么频繁,但是当它们发生时,它们可能比C ++中的大得多。 Judicious use of weak references can help, as well as assigning null to variables that are no longer needed. 明智地使用弱引用可以提供帮助,并将null赋给不再需要的变量。 However this leads to the second problem - if you then try to use the variable you will get a NullPointerException. 然而,这导致了第二个问题 - 如果您尝试使用该变量,您将获得NullPointerException。 This is more helpful than the segmentation fault you would probably get in C++, but is still an issue. 这比你在C ++中可能获得的分段错误更有帮助,但仍然是一个问题。

So all the things you learnt about memory management in C++ still apply in Java, but you have to do it for other resources too. 因此,您在C ++中学习内存管理的所有知识仍然适用于Java,但您也必须为其他资源执行此操作。

Turn garbage collection logging on and view the results in GCViewer . 打开垃圾收集日志记录并在GCViewer中查看结果。 This will show you how memory in your app is performing and if enough memory being cleaned up when the garbage collector runs. 这将向您显示应用程序中的内存如何执行以及垃圾收集器运行时是否清理了足够的内存。

GCViewer截图
(source: tagtraum.com ) (来源: tagtraum.com

I think I understand your mindset problem entirely, mostly because I have the exact opposite of it :) 我想我完全理解你的心态问题,主要是因为我它完全相反 :)

What I'd suggest is trying to create a sort of a paradigm transition from C++ to Java to enable yourself to write more of the actual code instead of managing objects themselves. 我建议尝试创建一种从C ++到Java的范式转换,以使自己能够编写更多的实际代码,而不是自己管理对象。

To give a concrete example, I'd assume that in C++ there's are certain things you do at the beginning and at the end of the object life cycle which means that you should most likely wrap those into their own methods ( not constructors/destructors, mind you! ) and first sort of "train" yourself to use those explicitly in C++. 举一个具体的例子,我假设在C ++中你在对象生命周期的开始和结束时都有某些事情,这意味着你最有可能将它们包装到自己的方法中( 而不是构造函数/析构函数,请注意! )并首先“训练”自己在C ++中明确使用它们。 Then, when moving to Java you can actually move over this method analogy quite easily with your other programming habits and instead of scratching your head with destructors and whatnot, just implement to base of those methods but leave them empty. 然后,当你转移到Java时,你可以很容易地用你的其他编程习惯来比较这种方法,而不是用析构函数和诸如此类的东西,只是实现这些方法的基础而是将它们留空。 This way you have a not-so-invisible mental marker for yourself that the object lifecycle is about to end and eventually when you sort of learn to trust that, you can remove it. 通过这种方式,您可以为自己创建一个不那么隐形的心理标记即对象生命周期即将结束,最终当您学会信任它时,您可以将其删除。 You don't even have to worry about overhead, JVM will optimize away those redundant method calls anyway as long as the body of the method is empty. 您甚至不必担心开销,只要方法的主体为空,JVM就会优化掉那些冗余的方法调用。

The next step of this, of course, is to extend the same to primitive values and going further from object lifecycle to method granularity level. 当然,下一步是将它扩展到原始值,并从对象生命周期进一步扩展到方法粒度级别。 To really condense to what I mean, here's an example class with those mental helpers applied: 为了真正浓缩到我的意思,这里是一个应用了这些心理助手的示例课程:

public class MentalHelpers {
    private MyFieldObject mfo;

    /**
     * Note the separate method for object creation.
     * This is actually good practice in general!
     */
    public MentalHelpers() {
        createObject();
    }

    private final void createObject() {
        mfo = new MyFieldObject();
    }

    private final void destroyObject() {
        // Do nothing! private or public, you decide.
    }

    public int incrementOne() {
        int i = 1;

        int ret = i++;

        freeInt(i);

        return ret;
    }

    private final freeInt(int i) {
        // Once again, do nothing!
    }
}

That's it, hopefully this is helpful. 就是这样,希望这很有帮助。

I think you should keep thinking C++ style. 我认为你应该继续思考C ++风格。 Object creation is expensive in Java, more so than in C++ since you don't have the option to allocate on the stack. Java中的对象创建是昂贵的,因为您没有在堆栈上分配的选项,因此在C ++中创建对象的成本更高。 Not sure if this is the answer you were looking for, though. 不过,不确定这是否是您正在寻找的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM