了解Java内存管理

Mic*_*dan 14 java garbage-collection jvm memory-leaks memory-management

Java程序员知道JVM运行垃圾收集器,而System.gc()只是建议JVM运行垃圾收集器.如果我们使用System.gc(),它不一定会立即运行GC.

如果我误解了Java的垃圾收集器,请纠正我.

除了依赖Java的垃圾收集器之外,是否还有其他方式进行内存管理?
如果您打算通过某种有助于管理内存的编程实践来回答这个问题,请这样做.

avi*_*iad 14

下面是我在日子里写的一些小摘要(我从一些博客上偷了它,但我不记得从哪里来 - 所以没有参考,对不起)

  1. 在Java中没有手动方式进行垃圾收集.
  2. 为了垃圾收集,Java Heap分为三代.这些是年轻一代,终身或老一代,以及彼尔姆地区.
  3. 新对象在年轻一代中创建,随后移至旧一代.
  4. 字符串池是在堆的Perm区域中创建的,垃圾收集可以在perm空间中进行,但依赖于JVM到JVM.
  5. 小垃圾收集用于将对象从Eden空间移动到Survivor 1和Survivor 2空间,Major集合用于将对象从年轻移动到终生.
  6. 每当主要垃圾收集发生应用程序时,线程在此期间停止,这将降低应用程序的性能和吞吐量.
  7. 在Java 6中,垃圾收集中几乎没有应用性能改进,我们通常使用JRE 1.6.20来运行我们的应用程序.
  8. JVM命令行选项-Xms,-Xmx用于设置Java堆的起始大小和最大大小.此参数的理想比例是1:1或1:1.5根据我的经验,例如,你可以有两种–Xmx,并–Xms为1GB或-Xms 1.2 GB和1.8 GB.

命令行选项: -Xms:<min size> -Xmx:<max size>


Naw*_*Man 14

关于Java内存管理最重要的事情是"取消"你的引用.

只有未引用的对象才会被垃圾回收.

例如,以下代码中的对象永远不会被收集,并且您的内存将满而为无所事事.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) objs.add(new Object());
Run Code Online (Sandbox Code Playgroud)

但是如果你没有引用那些对象......你可以在没有内存问题的情况下循环.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) new Object();
Run Code Online (Sandbox Code Playgroud)

所以,无论你做什么,请确保删除对不再使用的对象的引用(设置引用null或清除集合).

当垃圾收集器运行时最好留给JVM来决定.除非您的程序即将开始使用大量内存并且速度至关重要,否则您可能会建议JVM在进入之前运行GC,因为您可能会获得已经收集的内存以及额外的内存.另外,我个人认为没有理由跑System.gc().

希望这有帮助.


Ale*_*leš 7

只是添加到讨论中:垃圾收集不是Java中唯一的内存管理形式.

过去,在实现内存管理时,已经努力避免Java中的GC(请参阅Java的实时规范(RTSJ)).由于性能开销或GC引入的延迟,这些工作主要致力于Java中不适合的实时和嵌入式编程.

RTSJ的特点

  • 不朽和范围内存管理 - 请参阅下面的示例.
  • GC和Immortal/Scoped Memory可以与一个应用程序共存
  • RTSJ需要经过特殊修改的JVM.

RTSJ优势:

  • 低延迟,没有GC暂停
  • 提供可预测的性能,能够满足实时系统要求

为什么RTSJ失败/没有产生重大影响:

  • Scoped Memory概念很难编程,容易出错并且难以学习.
  • 实时GC算法的进展减少了GC暂停时间,使得实时GC在大多数实时应用程序中取代了RTSJ.但是,Scoped Memories仍然用于不容忍延迟的地方.

范围内存代码示例(取自范围内存使用示例):

import javax.realtime.*;
public class ScopedMemoryExample{

    private LTMemory myMem;

    public ScopedMemoryExample(int Size) {

       // initialize memory
       myMem = new LTMemory(1000, 5000); 
    }

public void periodicTask() {

  while (true)) {
    myMem.enter(new Runnable() {
        public void run() {
          // do some work in the SCOPED MEMORY
          new Object();
          ...
          // end of the enter() method, the scoped Memory is emptied.  
        }
    });
  }


}
}
Run Code Online (Sandbox Code Playgroud)

这里,调用的ScopedMemory实现LTMemory是预先分配的.然后一个线程进入作用域内存,分配仅在计算期间所需的临时数据.在计算结束之后,线程离开作用域内存,该内存立即使特定ScopedMemory的整个内容被清空.没有引入延迟,在恒定时间内完成,例如可预测的时间,不触发GC.