JVM内存详解

内存组成

这里写图片描述

内存区主要可以划分为5个区域,如上图。

  • java堆(Heap)
    这里写图片描述
    堆内存是运行时的数据区域。有新生代和旧生代组成,存储new对象的地方。这块是GC的主要区域。从存储的内容我们可以很容易知道,方法区和堆是被所有java线程共享的。
    持久带PermGen space属于非堆内存,是指内存的永久保存区域。这块内存主要是被JVM存放Class和Meta信息的。Class在被Loader时就会被放到PermGen space中,它和存放类实例的堆内存区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的应用程序下用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么很可能就会产生PermGen space溢出的异常了。

  • 方法区(Method Area)
    用于存储应用程序的所有类结构信息,虽然JVM规范把方法区描述为堆的一个逻辑部分,但它属于非堆内存。存储信息包括常量池、静态变量、构造函数等。它是在 Java 虚拟机启动时创建,由所有线程共享。

  • JVM栈(Stack)
    这里写图片描述
    JVM栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java线程栈。
    在这个java栈中又会包含多个栈帧,每运行一个方法就创建一个栈帧,每个栈帧对应着当前线程栈对每个方法的每次调用。方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程。所以java栈是每个线程私有的,线程生就生,线程灭就灭。栈中的栈帧随着方法的结束也会撤销,内存自然就跟着回收了。
    栈帧又分为局部变量区和操作数栈两部分。局部变量区用于存放方法中的局部变量和参数;操作数栈用于存放方法执行过程中产生的中间结果;每个线程栈大小, JDK1.5+ 默认大小为 1M。一般来说如果栈不是很深的话, 1M 是绝对够用了的。

  • 程序计数器(PC Register)
    用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的。

  • 本地方法栈(Native Method Stack)
    和java栈的作用差不多,只不过是为JVM使用到的native方法服务的。

回收算法和过程

当一个URL被访问时,内存申请过程 如下:
(1)JVM会试图为相关Java对象在Eden中初始化一块内存区域。

(2) 当Eden空间足够时,内存申请结束。否则到下一步。

(3)JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区。

(4)Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区。

(5)当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)。

(6)完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误。

友情链接:http://blog.youkuaiyun.com/tonytfjing/article/details/44278233

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值