1、内存字眼
java里的内存概念很多,有:java内存区,gc内存区,JMM内存模型,cpu内存模型,对象内存布局。很容易混淆。
比如突然问:运行时数据区,堆和栈,新生代和老年代,工作内存与主内存,高速缓存与主内存,对象在内存中的存储布局。就找不到北了,都不知道哪个属于哪类范畴和概念。很多概念里都有内存这个字眼,真容易混淆起来,一脸懵逼。(之前我就一直混淆,懵逼)
通过对jvm的学习,下文会把这些概念进行描述和区分
2、内存概念
- java内存区域(运行时数据区域)
- gc内存区(垃圾回收)
- CPU内存模型
- JMM内存模型
- 对象内存布局
2.1、java内存区域(运行时数据区域)
2.1.1 程序计数器
可以看做是当前线程所执行的字节码的行号指示器。每个线程都有自己的程序计数器(线程私有)
2.1.2 Java虚拟机栈(栈)
线程私有,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息
局部变量表:存放了编译器可知的各种基本数据类型、对象引用(指针)、return Address类型(执行字节指令地址)
2.1.3 Java堆(堆)
堆内存区域的唯一目的就是存放对象实例, 所有对象实例以及数组都要在堆上分配(java虚拟机规范是这个规定但是随着技术发展现在已经不那么绝对),线程共享
注:java堆是垃圾回收器管理的主要区域,也被叫做“GC堆”。
对象的内存布局:对象头(Header),实例数据,对齐填充
补:对象,实例,引用的概念
MyClass myClass=new MyClass();
new的时候在堆中新建了一个对象。这个对象是MyClass的实例。其中myClass是该对象的引用。
2.1.4 方法区
线程共享,用于存储已经被虚拟机加载的:类信息、常量、静态变量、即使编译器编译后的代码等数据
运行时常量池:方法区的一部分,用于存放编译期生成的各种字面量和符号引用
2.2 cpu 内存模型
多处理器的内存模型,内存模型是一个抽象概念。
2.3 java 内存模型(JMM)
c/c++直接作用在cpu或者操作系统的内存模型上,java自己做了JMM抽象。
java内存模型JMM包括两部分,一个是内存结构,一个是变量访问规则。这里主要描述内存结构,对访问规则不展开熬述。
- 主内存:java内存模型规定了所有的变量都存储在主内存中
- 工作内存:线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读,写)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同工作线程也不能直接访问对方工作内存中的变量。线程间的变量值传递需要通过主内存
- 变量:这里说的变量指的是共享变量包括:实例字段、静态字段、构成数组对象的元素。不包括形参和局部变量
补充:
- 这里的主内存对应java堆中的对象实例的数据部分
- 工作内存对应 java栈
知识点:volatile变量
java 内存模型对volatile定义了特殊的访问规则。
第一,可见性规则,保证volatile对所有线程可见,即一线程改变了该变量值,新值对于其它线程来说是可以立即得知的。
第二,volatile禁止指令重排优化。
2.4、GC内存区
GC垃圾回收的内如很多包括:垃圾定位算法,内存分配结构,垃圾回收算法,垃圾回收器。这里只简单面熟gc内存区
- 新对象,实例化时内存分配在 eden 区,eden区耗尽的时,触发minor GC,将存活的对象放到Survivor的From区,清空Eden
- minor gc 时把eden区和from区剩余的对象copy到to区,from to 功能交换。反复多次复制后还存活的对象(比如15次), 进入到老年代
- 当老年代的空间耗尽时,触发Major gc
补充:
- 新生代垃圾回收器minor gc
- 老年代垃圾回收器majar gc 速度比minor gc 慢很多
- full gc:清理整个堆空间—包括年轻代和永久代
- 永久代 是hotspot 在jdk8之前的概念。
付
[1]深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)周志明著