[TOC]
(一)java 内存区域治理
C/C++ 每一个 new 操作都须要本人去 delete/free,而 java 外面有虚拟机主动治理内存,不容易呈现内存透露或者溢出的问题,然而不容易呈现不代表不呈现,理解虚拟机怎么应用和治理内存是非常重要的是,对程序优化或者问题排查有帮忙。
运行时区域次要分为:
-
线程公有:
- 程序计数器:
Program Count Register
, 线程公有,没有垃圾回收 - 虚拟机栈:
VM Stack
,线程公有,没有垃圾回收 - 本地办法栈:
Native Method Stack
, 线程公有,没有垃圾回收
- 程序计数器:
-
线程共享:
- 办法区:
Method Area
,以HotSpot
为例,JDK1.8
后元空间取代办法区,有垃圾回收。 - 堆:
Heap
,垃圾回收最重要的中央。
- 办法区:
1.1 程序计数器
空间很小,以后线程执行的字节码的行号指示器(线程独有,批示以后执行到哪,下一步须要执行哪一个字节码),分支,循环,跳转,异样解决,线程复原都须要依赖它。
线程公有:java
多线程其实是线程轮流切换并调配处理器执行工夫的形式实现,一个核一个具体的工夫点,只会执行一个线程的指令。线程切换须要保留和复原正确的执行地位(爱护和复原现场),所以不同的线程须要不同的程序计数器。
- 执行
java
办法时,程序计数器记录的是正在执行的字节码指令地址 - 执行
Native
办法,程序计数器为空
惟一一个没有规定任何 OutOfMemory
的区域,也没有 GC(垃圾回收)。
1.2 虚拟机栈
线程公有,生命周期和线程一样,次要是记录该线程 Java 办法执行的内存模型。虚拟机栈外面放着好多栈帧。留神虚拟机栈,对应是 Java 办法,不包含本地办法。
一个 Java 办法执行会创立一个栈帧,一个栈帧次要存储:
- 局部变量表
- 操作数栈
- 动静链接
- 办法进口
每一个办法调用的时候,就相当于将一个栈帧放到虚拟机栈中(入栈),办法执行实现的时候,就是对应着将该栈帧从虚拟机栈中弹出(出栈)。
每一个线程有一个本人的虚拟机栈,这样就不会混起来,如果不是线程独立的话,会造成调用凌乱。
大家平时说的 java 内存分为堆和栈,其实就是为了简便的不太谨严的说法,他们说的栈个别是指虚拟机栈,或者虚拟机栈外面的局部变量表。
局部变量表个别寄存着以下数据:
- 根本数据类型(
boolean
,byte
,char
,short
,int
,float
,long
,double
) - 对象援用(reference 类型,不肯定是对象自身,可能是一个对象起始地址的援用指针,或者一个代表对象的句柄,或者与对象相干的地位)
- returAddress(指向了一条字节码指令的地址)
局部变量表内存大小编译期间确定,运行期间不会变动。空间掂量咱们叫 Slot(局部变量空间)。64 位的 long 和 double 会占用 2 个 Slot,其余的数据类型占用 1 个 Slot。
异样:
- StackOverflowError:线程申请的栈深度大于虚拟机容许的深度
- OutOfMemoryError:内存不足
1.3 本地办法栈
和虚拟机栈相似,对应本地办法,Native
,虚拟机标准容许语言,应用形式和数据结构不同,有些可能将虚拟机栈和本地办法栈合并。
异样与虚拟机栈统一:
- StackOverflowError:线程申请的栈深度大于虚拟机容许的深度
- OutOfMemoryError:内存不足
1.4 java 堆
堆是内存治理最大的一块,线程共享。
虚拟机标准中说,所有的对象实例和数组都要在堆上调配。然而实际上 不是所有的对象都在堆上调配 ,这个和 JIT 编译器的倒退和逃逸剖析技术相干。Why?
// TODO
堆的细分:新生代,老年代,再细分有 Eden,From survivor,To survivor 等。
堆中也有可能有线程公有的区域,调配缓冲区。
物理上能够不间断,然而逻辑上是间断的。
异样:
- OutOfMemoryError:内存不足
1.5 办法区
名为非堆,然而理论和堆一样,是线程共享的区域,次要存贮以下信息:
- 已被虚拟机加载的类信息
- 常量
- 动态变量
- 即时编译器编译后的代码
办法区不等于永恒代,批示 Hotspot 虚拟机将 GC 分代收集拓展到办法区,也就是用永恒代实现了办法区,而其余的虚拟机不肯定,不是固定的。JDK1.7 将永恒代的字符串常量移出了。
办法区回收垃圾的成果不是很好,能够抉择不回收,虚拟机能够决定,当然也可能产生内存透露。
异样:
- OutOfMemoryError:内存调配异样
1.5.1 运行时常量池
运行时常量池时办法区的一部分,然而不是全副,Class
文件次要包含:
- 类的版本
- 字段
- 办法
- 接口
- 常量池,寄存编译产生的字面量和符号援用,个别除了形容 Class 文件的符号援用,还有间接援用也在外面。是动静的,运行时能够产生,比方 String.intern()办法。
异样:
- OutOfMemoryError:内存调配异样
(二)间接内存
不是虚拟机运行时数据区,也不是标准规定的区域,然而应用频繁且可能会有 OutOfMemoryError:内存调配异样呈现。
比方,NIO(1.4)基于 Channel 与 Buffer 的 I /O,能够用 Native 函数间接调配堆外内存,通过存储在 Java 堆中的 DirectByteBuffer 对象作为援用来操作,进步性能,不须要 Java 堆和 Native 堆都来回复制数据。
间接内存受物理的内存,或者处理器寻址空间之类的限度。
本文系 JVM 学习相干笔记,整顿来自周志明老师的《深刻了解 Java 虚拟机》,无比钦佩,强烈推荐!
【作者简介】:
秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使迟缓,驰而不息。这个世界心愿所有都很快,更快,然而我心愿本人能走好每一步,写好每一篇文章,期待和你们一起交换。
此文章仅代表本人(本菜鸟)学习积攒记录,或者学习笔记,如有侵权,请分割作者核实删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有谬误之处,还望指出,感激不尽~