Java内存大体分为:堆内存(Heap) 栈内存(Stack)
内存细分:
虚拟机栈
本地方法栈
PC寄存器
方法区
堆区
再分:
线程共享区:方法区,堆区。随着虚拟机启动而创建,随着虚拟机退出而销毁,并且为进程的所有子线程共享
线程独享区:虚拟机栈,本地方法栈,PC寄存器,这些数据与线程一一对应,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁
一 、线程独享区
PC寄存器:任意时刻,一个虚拟机线程只会执行一个方法的代码,这个正在被执行的方法被称为线程的当前方法,而PC寄存器存储的就是当前方法经过JVM汇编的后字节码指令的地址
虚拟机栈:栈中元素叫做栈帧,线程再调用Java方法时,会为每个方法创建一个栈帧。栈帧:存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法被调用和完成的过程,都对应着一个栈帧从虚拟机栈上入栈和出栈的过程。生命周期:虚拟机栈与线程同步。栈帧( Frame)是用来存储数据和部分过程结果的数据结构
本地方法栈:Java 虚拟机实现可能会使用到传统的栈(通常称之为“ C Stacks”)来支持 native 方法( 指使用 Java 以外的其他语言编写的方法)的执行,这个栈就是本地方法栈( Native Method Stack)。当 Java 虚拟机使用其他语言(例如 C 语言)来实现指令集解释器时,也会使用到本地方法栈。本地方法栈和虚拟机栈所发挥的作用是非常相似的,区别是虚拟机栈执行Java方法,而本地方法栈则为虚拟机使用的Native方法服务,在sun hotspot 虚拟机中已经把两者合二为一了,本地方法栈区也会抛出StackOverFlowError和OutOfMemeoryError异常
二 、线程共享区
Heap:
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此区域唯一目的就是存放对象实例,几乎所有对象的实例都在这分配内存。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为GC堆,Java 堆在虚拟机启动的时候就被创建,它存储了被自动内存管理系统( Automatic Storage Management System,也即是常说的“ Garbage Collector(垃圾收集器)”)所管理的各种对象。 Java 堆的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩
方法区:它存储了每一个类的结构信息,例如运行时常量池( Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法。方法区是堆的逻辑组成部分
JVM布局:
每一个运行再JAVA虚拟机里的线程都拥有自己的线程栈,这个线程栈包含了这个线程调用的方法当前执行点相关的信息
堆上包含在Java程序中创建的所有对象,无论是哪一个对象创建的。这包括原始类型的对象版本。如果一个对象被创建然后赋值给一个局部变量,或者用来作为另一个对象的成员变量,这个对象任然是存放在堆上。
变量:
1、成员变量(实例变量,属性)
2、本地变量(局部变量)
3、类变量(静态属性)
仅有本地变量放在线程栈上
从JVM运行时内存进行划分:堆内存和非堆内存
堆内存:堆试运行时数据区域,所有实例和数组的内存均从此处分配。堆实在JAVA虚拟机启动时创建的,
非堆内存:再JVM中堆之外的内存称为非堆内存(non-heap)
从对象的角度来说JVM内存大致分为3块:
Permanent Generation: 持久代
New Generation :年轻代
Tenured Geneeation :老年代
持久带位于:non-heap区
new和old是Java应用的Heap区用来存放类的实例Instance的
new 尽可能快速的手机哪些生命周期短的的对象:
eden space --> from survivor space -> to survivor space ->
当To也满了就从From区复制过来并且依然存货的对象到Old区,从而From和To救助空间互换角色,维持活动的对象将在救助空间不断复制,直到最终转入Old域。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。每一次垃圾回收后,Eden Space都会被清空。
Old区用于存放长寿的对象,在New区中经历了N次垃圾回收后仍然存活的对象,就会被放到Old区中;如那些与业务信息相关的对象,包括Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。
以上任何一个空间不够时都会促进jvm执行垃圾回收,基于类型不同,我们将垃圾回收分为:
Minor GC(young gc): 回收new Generation内存空间(eden , from to )
Full GC(): 回收new Generation和Tenured Generation、PermGen内存空间
-
Minor GC(young gc)
当新对象生成,并且在Eden申请空间失败时,就会触发Minor GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区,然后整理Survivor的两个区。这种方式的GC是对New区的Eden区进行,不会影响到Old区。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的Minor GC会频繁进行。一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。 -
Full GC
Full GC要对整个Heap区进行回收,包括New、Old和PermGen,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数。在对JVM性能调优的过程中,很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC:
·Tenured区被写满
·PermGen区被写满
·System.gc()被显示调用
·上一次GC之后Heap的各域分配策略动态变化
需要注意的是,Full GC与YoungGC是无法完全区分开来的,很多情况下,Full GC是由YoungGC导致的。例如在Eden Space中的对象经历过几次垃圾回收,依然还存活,就会移动到Tenured区,而如果此时Tenured区空间不够,就会出发垃圾回收,过程如下图所示:
survivor space:其实是临时存储空间,几次垃圾回收依然没回收掉的对象被过渡到老年代