浅谈JVM的实现与垃圾回收机制(2)

大多数的应用中持有的对象很大部分是短生命周期的,这被称为“Weak generational hypothesis”。在垃圾回收期间分析应用中所有的对象是一件缓慢而耗时的工作,因此可以将短生命周期的对象在其被创建时就分隔出来。因此New Generation可以进一步划分为:

Eden Space (Eden空间):所有的新创建的对象都存在与此。当其变满时,minor GC便会出现。然后所有仍然被引用的对象被移动到幸存者空间中。

Survivor Spaces (幸存者空间):对不同的JVM而言,幸存者空间的实现方式也不尽相同,但基本原理都是相同的。New Generation中的每一个GC都会增加幸存者空间中的对象年龄。如果对象的年龄超过某个特定值(默认情况下是15),该对象会被移往Old Generation。

New Generation中的GC也被称为minor GC。使用New Generation的好处是可以减少分片带来的影响。

Old Generation

任何从New Generation中的幸存者空间中幸存下来的对象会被送往Old Generation。Old Generation通常比New Generation大很多。存在于Old Generation中的GC也被称为Full GC。Full GC可以执行“Stop The World”机制,并且通常会占用更长的时间,因此Full GC也称为绝大不多的JVM可以进行优化的地方。

Permanent Generation

Permanent Generation用于存放类的元信息。在Java 8中其被metaspace所取代。通常Permanent Generation无需为了确保其有足够空间而被优化,但是当类没有被正确上传时,其仍有可能发生内存泄露的情况。

Java中的内存泄露

Java所支持的垃圾回收机制有效的减少了内存溢出的发生。内存溢出意味着当分配出去的内存却永远都没有被回收。虽然JVM能够自动回收那些没有被使用的对象所占用的内存,但事实上,Java中还是回发生内存溢出现象。假设存在一个有效的(但是没有被使用)对象引用指向一个没有被使用的对象,这会导致该对象一直占用着内存。

举例来说,当一个方法需要运行很长的时间(或者永远都在运行),方法中的局部变量可以在长时间的持有对象引用,而这远超出自己实际需要的时间。代码如下:

public static void main(String args[]) { int bigArray[] = new int[1000]; int result = compute(bigArray); // We no longer need bigArray. It will get garbage collected when // there are no more references to it. Because bigArray is a local // variable, it refers to the array until this method returns. But // this method doesn't return. So we've got to explicitly get rid // of the referenceourselves, so the garbage collector knows it can // reclaim the array. bigArray = null; // Loop forever, handling the user's input for(;;) handle_input(result); }

内存泄露也会出现在你使用类似于HashMap这类数据结构时将一个对象与另一个对象相关联的情况。即使两个对象都不再被需要了,这种关联仍会存在于hash表中,除非hash表本身被垃圾回收器回收了,否则其中的关联对象会一直占用内存。如果hash表会运行相当长的时间的话,那么内存泄露便会发生。

System.gc() and finalize() 可以手动执行垃圾回收嘛?

这应该是个有意思的问题。答案是可以,也不可以。我们可以调用System.gc()方法建议JVM执行垃圾回收。然后,并没有任何保证说JVM一定会执行该操作。作为开发者,我们无法知晓JVM是否执行了我们的代码。并且,通常认为使用System.gc()是个很不明智的做法。

finalize()

finalize()方法存在于java.lang.Object类中,可以被所有对象所使用。默认情况下其不执行任何动作。当垃圾回收器确定了一个对象没有任何引用时,其会调用finalize()方法。但是,finalize方法并不一定会被执行,因此也不建议覆写finalize()该方法。

References

Java In a Nutshell, 6th Edition

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/76848deda253034d1f005e1df3dc6aa2.html