java内存结构,也就是运行时的数据区:方法区、堆、java栈、本地方法栈、程序计数器
程序计数器:是一个数据结构,存储的是程序的内存地址,由于java支持多线程,当线程被中断后继续执行需要记录内存地址,每个线程都有一个独立的程序计数器,这类内存称为“线程私有”的内存。是线程安全的
java栈:java栈总是与线程关联在一起,当创建一个线程jvm就会为该线程创建对应的java栈,java栈中包含了多个栈帧,这些栈帧跟每个方法关联起来的,每运行一个方法就会创建一个栈帧,每个栈帧包含局部变量、数据栈、返回值等,每当方法执行完,弹出方法返回值,清除栈帧。java栈的栈顶是活动栈,也就是当前正在执行的方法,PC寄存器也会指向这个地址。java栈是与线程对应起来的,栈数据不是线程共享,不需要关系数据一致性,不存在同步锁的问题。如果栈深度大于虚拟机允许的最大深度,则抛出StackOverFlowError异常
堆:堆是JVM管理的最大的内存,是被所有java线程共享,是线程不安全的,是JVM启动时创建的。是存储java对象的地方,java堆是gc管理的主要区域,由于gc采用分代收集算法,所以堆还分为年轻代和老年代;年轻代分为Eden,from survivor,to survivor.
年轻代:所有新生成的对象首先放在年轻代
年老代:在年轻代经过N次垃圾回收后仍然活着的对象,复制到年老代
当一组对象生成时,内存申请过程如下:
1).JVM会试图为相关Java对象在年轻代的Eden区中初始化一块内存区域。
2).当Eden区空间足够时,内存申请结束。否则执行下一步。
3).JVM试图释放在Eden区中所有不活跃的对象(Young GC)。释放后若Eden空间仍然不足以放入新对象,JVM则试图将部分Eden区中活跃对象放入Survivor区。
4).Survivor区被用来作为Eden区及年老代的中间交换区域。当年老代空间足够时,Survivor区中存活了一定次数的对象会被移到年老代。
5).当年老代空间不够时,JVM会在年老代进行完全的垃圾回收(Full GC)。
6).Full GC后,若Survivor区及年老代仍然无法存放从Eden区复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“Out of Memory”。
方法区:方法区存放了要加载的类的信息(名称,修饰符等)、类中定义的静态常量、定义为final的静态常量、类中的Field信息、类中方法信息,当在程序中通过Class对象获取信息时都是从方法区取的数据,方法区是被java线程共享,不像其他频繁被gc回收,也是堆的一部分是堆的永久区Perment,超过大小时会报OutOfMemory。参数设置有-XX:PermSize指定初始值,-XX:MaxPermSize指定最大值
本地方法栈:是支持native方法,比如在java中调用C/C++;