JAVA内存模型

来源:互联网 发布:淘宝哪个男装店好 编辑:程序博客网 时间:2024/05/16 16:14

 Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。

堆内存(Heap Memory)是在Java 虚拟机启动时创建, 堆是Java代码可及的内存,留给开发人员使用的。
非堆内存(Non-heap Memory)是在JVM堆之外的内存。

JVM 内存包含如下几个部分:

  • 堆内存(Heap Memory): 存放Java对象
  • 非堆内存(Non-Heap Memory): 存放类加载信息和其它meta-data
  • 其它(Other): 存放JVM 自身代码等
如图:

          


eclipse中对于Heap内存的设置和Non-Heap的设置,如图:

       

 -XX:MaxPermSize 设置Non-Heap大小

  Heap 内存  -Xms   -Xmx

默认空余堆内存小于40%时,JVM 就会增大堆直到-Xmx 的最大限制,可以由 -XX:MinHeapFreeRatio 指定。 

默认空余堆内存大于70%时,JVM 会减少堆直到-Xms的最小限制,可以由 -XX:MaxHeapFreeRatio 指定。

Java的内存管理实际上就是变量对象的管理,其中包括对象的分配和释放。

如图:
组成:


Heap->Young和Old

     Old:主要存放应用程序中生命周期长的内存对象


     Young->Eden,From和To  

     Eden:主要用来存放新生的对象。

Survivor Spaces(from、to):它们的大小总是一样,它们用来存放每次垃圾回收后存活下来的对象



   垃圾回收:

Copying的算法,速度快

复制(copying)
    原理:
把内存空间划分为2个相等的区域,每次只使用一个区域。垃圾回收时,遍历当前使用区域,把正在使用的对象复制到另外一个区域。
    优点:
不会出现碎片问题。
   缺点:
(1)暂停整个应用。
(2)需要2倍的内存空间。
过程:
Young->
Eden拷贝到某个SurvivorSpace->
Survivor Space空间满了后剩下的live对象就被直接拷贝到OldGeneration中去->
每次GC后,Eden内存块会被清空。


mark-compact的算法,速度慢些,但减少内存要求

标记-压缩(Mark-Compact)
    第一阶段:同标记-清扫,标记活的对象,
第二阶段:这个阶段将所有做了标记的活动对象整理到堆的底部
   优点:
(1)避免标记扫描的碎片问题;
(2)避免停止复制的空间问题。

  
Old->0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾
1级或以上为部分垃圾回收,只会回收Young中的垃圾。
内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。


   Java编程建议

SoftReference、 WeakReference、 PhantomReference引用类型

根据GC的工作原理,我们可以通过一些技巧和方式,让GC运行更加有效率,更加符合应用程序的要求。一些关于程序设计的几点建议:

1)最基本的建议就是尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为 null.我们在使用这种方式时候,必须特别注意一些复杂的对象图,例如数组,队列,树,图等,这些对象之间有相互引用关系较为复杂。对于这类对象,GC 回收它们一般效率较低。如果程序允许,尽早将不用的引用对象赋为null,这样可以加速GC的工作。

2)尽量少用finalize函数。finalize函数是Java提供给程序员一个释放对象或资源的机会。但是,它会加大GC的工作量,因此尽量少采用finalize方式回收资源。

3)如果需要使用经常使用的图片,可以使用soft引用类型。它可以尽可能将图片保存在内存中,供程序调用,而不引起OutOfMemory.

4)注意集合数据类型,包括数组,树,图,链表等数据结构,这些数据结构对GC来说,回收更为复杂。另外,注意一些全局的变量,以及一些静态变量。这些变量往往容易引起悬挂对象(dangling reference),造成内存浪费。

5)当程序有一定的等待时间,程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。使用增量式GC可以缩短Java程序的暂停时间。





0 0
原创粉丝点击