jvm讲解-jvm内存结构详解
jdk1.8以前的jvm的内存结构图(有方法区的概念):
以上这个图可以看出内存结构的构成:
- 方法区
- 堆
- 虚拟机栈
- 程序计数器
- 本地方法栈
- 直接内存
下面开始详细介绍这些内容;
jdk1.8以后的jvm的内存结构图(引入了元空间概念),下面有具体的讲解。
1. 方法区(线程共享)
1.1 定义:
被所有线程共享的一块内存区域。
用于存储已被虚拟机加载的类信息,常量,静态变量等。
这个区域的内存回收目标主要针对常量池的回收和对类型的卸载。
当方法区无法满足内存分配需求时,则抛出OutOfMemoryError异常。
JDK1.7中,已经把放在永久代的字符串常量池移到堆中。
JDK1.8撤销永久代,引入元空间。
1.2 组成
jdk 1.8 后有元空间的概念,方法区不再占用jvm内存,占用本地内存。
1.3 方法区内存溢出
1.8 以前会导致永久代内存溢出
永久代内存溢出 java.lang.OutOfMemoryError: PermGen space
修改永久代内存命令 -XX:MaxPermSize=8m
1.8 之后会导致元空间内存溢出
元空间内存溢出 java.lang.OutOfMemoryError: Metaspace
修改元空间内存命令 -XX:MaxMetaspaceSize=8m
场景:Spring,Mybatis 底层都用到了动态代理,动态生成类的字节码。
1.4 运行时常量池
常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量 等信息
运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址(字符串在运行时,用到了才会存到堆中的StringTable中--相当于懒加载,串池中值是唯一的)
反编译class 命令:Javap –v HelloWord.class
1.5 练习了解StringTable
先看几道题:
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b"; //javac 在编译期间的优化(常量不可能再变),结果已经在编译期确定为ab
s4 //new StringBuilder.append(“a”).append(“b”).toString() new String(“ab”)
s4 //是新对象,在堆中。常量在常量池中
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();
问题如下:
System.out.println(s3==s4);//false
System.out.println(s3==s5);//ture
System.out.println(s3==s6);//ture
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
// 问题如下:
System.out.println(x1 == x2); //jdk1.6 //false
System.out.println(x1 == x2); //jdk1.8 //ture
1.6 StringTable 特性
1.常量池中的字符串仅是符号,第一次用到时才变为对象
2.利用串池的机制,来避免重复创建字符串对象
3.字符串变量拼接的原理是 StringBuilder (1.8)
4.字符串常量拼接的原理是编译期优化
5.可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池
jdk1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回
jdk1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回
1.7 StringTable 位置
StringTable本质也就是常量池,以前存在于方法区中,jdk1.7以后就进行了修改。放到了堆中,因为字符串比较多,垃圾回收能够及时清理多余的数据。
1.8 StringTable 垃圾回收
-XX:+PrintStringTableStatistics查看字符串参数的大小信息
-XX:+PrintGCDetails -verbose:gc 垃圾回收的详细信息(次数,时间。。。)
1.9 StringTable 性能调优
调整 -XX:StringTableSize=桶个数,桶数越多会越快(减少了比对的情节)
考虑将字符串对象是否入池(string.intern())
2. 堆
2.1 定义:
Heap 堆
通过 new 关键字,创建对象都会使用堆内存
特点:1.它是线程共享的,堆中对象都需要考虑线程安全的题
2.有垃圾回收机制
2.2 堆内存溢出
堆内存溢出报错:java.lang.OutOfMemoryError
堆内存默认大小是4g,修改堆内存大小命令:-Xmx256m
2.3 堆内存诊断
1. jps 工具
查看当前系统中有哪些 java 进程
2. jmap 工具
查看堆内存占用情况命令:jmap - heap 进程id
3. jconsole 工具
图形界面的,多功能的监测工具,可以连续监测
案例
垃圾回收后,内存占用仍然很高,定位问题:jvisualvm
3. 虚拟机栈
3.1 定义
Java Virtual Machine Stacks (Java 虚拟机栈)
每个线程运行时所需要的内存,称为虚拟机栈
每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
问题辨析
- 垃圾回收是否涉及栈内存? 不涉及,运行后会自动弹出
- 栈内存分配越大越好吗? 不是,内存一定,栈内存分配的大,线程数就会变少
- 方法内的局部变量是否线程安全? 普通变量是安全的。静态变量是共享的不安全。
如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
3.2 栈内存溢出
栈帧过多导致栈内存出(递归)
栈帧过大导致栈内存出--基本上不会出现
栈内存默认大小是1M,修改栈内存大小 -Xss256k
3.3 线程运行诊断
案例1: cpu 占用过多
定位:1.用top定位哪个进程对cpu的占用过高
2.ps H -eo pid,tid,%cpu | grep 进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高,线程需要转成16进制配合jstack)
3.jstack 进程id,可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号
4.程序计数器
4.1 定义
Program Counter Register 程序计数器(寄存器)
作用,是记住下一条jvm指令的执行地址(有时间片的概念,在一定时间内还没运行完就会暂时释放线程)
特点:1.是线程私有的 2.不会存在内存溢
4.2 作用
0: |
getstatic |
#20 |
// PrintStream out = System.out; |
3: |
astore_1 |
// -- |
|
4: |
aload_1 |
// out.println(1); |
|
5: |
iconst_1 |
// -- |
|
6: |
invokevirtual #26 |
// -- |
|
9: |
aload_1 |
// out.println(2); |
|
10: |
iconst_2 |
// -- |
|
11: |
invokevirtual #26 |
// -- |
|
14: |
aload_1 |
// out.println(3); |
|
15: |
iconst_3 |
// -- |
|
16: |
invokevirtual #26 |
// -- |
|
19: |
aload_1 |
// out.println(4); |
|
20: |
iconst_4 |
// -- |
|
21: |
invokevirtual #26 |
// -- |
|
24: |
aload_1 |
// out.println(5); |
|
25: |
iconst_5 |
// -- |
|
26: |
invokevirtual #26 |
// -- |
|
29: |
return |
||
5.本地方法栈
本地方法:不是用Java语言编写的方法,因为Java语言是有一定限制的,有些情况下它是不能直接和操作系统打交道。这时就需要调用一些用C或C++编写的方法去跟操作系统底层打交道。Java语言可以调用这些本地方法间接的调用操作系统底层的一些功能。
本地方法栈:本地方法运行时所需要的内存就是本地方法栈。
6.直接内存
6.1 定义
直接内存Direct Memory
常见于 NIO 操作时,用于数据缓冲区
分配回收成本较高,但读写性能高
不受 JVM 内存回收管理 System.gc();
6.2 分配和回收原理
使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦 ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调 用 freeMemory 来释放直接内存
jvm讲解-jvm内存结构详解相关推荐
- JVM之内存结构详解
对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.今天开始,<JVM详解>系列开启,带大家深入了解JVM相 ...
- jvm之java内存区域详解篇guide哥yyds
jvm 一.java内存区域详解 1.运行时数据区域 线程私有的: 虚拟机栈 本地方法栈 程序计数器 线程共享的: 堆 方法区 直接内存(非程序运行时数据区的一部分) 1.1什么是程序计数器 程序计数 ...
- JVM总结之内存区域详解
一.概述 1 运行时数据区概述 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域.JDK 1.8 和之前的版本略有不同,下面会介绍到. 线程私有的: 程序计数器 ...
- [精]Oracle 内存结构详解
内存结构 现代计算机中,CPU 对内存的访问速度要比从磁盘的速度快千倍,因此 Oracle 对于数据的访问 也尽量都在内存中完成,而不是直接修改硬盘上的数据.内存内容在合适的时候再同步到磁盘. Ora ...
- JVM 运行时内存空间详解——元空间
通过上一篇文章,我们大体了解了JVM的整体架构,其分为:元数据(JDK7是方法区).堆.虚拟机栈.本地方法栈.程序计数器几个部分. 本篇文章,咱们对元空间进行剖析,一探究竟. 1. 元空间介绍 在JD ...
- jvm堆外内存排查详解
文章目录 前言 一.堆外内存排查 1.背景 2.内存对比 3.堆外内存检查 4.排查堆外内存 5.glibc内存泄露 结尾 前言 内存泄漏想必大家并不陌生,对于jvm的内存泄漏,有很多排查手段和方便的 ...
- 【JVM】Java内存区域详解(通俗易懂系列)
Java虚拟机拥有管理内存的权利. 一.运行时数据区 在Java程序执行的过程中,Java虚拟机会将它管理的内存分为若干个不同数据区域(JDK1.8与之前版本不同) 线程私有: 虚拟机栈 本地方法栈 ...
- Oracle内存结构详解(三)--管理Oracle Share Pool
SGA中的共享池由库缓存(Library Cache).字典缓存(Dictionary Cache).用于并行执行消息的缓冲以及控制结构组成. Shared Pool的大小由参数SHARED_POOL ...
- [java] 虚拟机(JVM)底层结构详解[转]
[java] 虚拟机(JVM)底层结构详解[转] 本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 在以前的博客里面,我们介绍了在java领 ...
- JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)
JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...
最新文章
- c# 一些控件常用屬性
- java并发编程——并发容器类介绍
- RobotFramework自动化框架—数据驱动测试
- POJ2528的另一种解法(线段切割)
- 经典|图解Linux内存性能优化核心思想
- java中字符串的操作_java中字符串的操作
- web项目的创建和发布
- VS2015 Cordova Ionic移动开发(五)
- ISA Server 2006 部署步骤
- 面试中,答不出产品方法论?4个方法教给你...
- Kinaba及X-Pack插件安装
- 服务器2003系统U盘安装方法,u盘winpe下安装windows server 2003详细教程
- 《高等数学》:推导第七版下册第十章第四节的“利用曲面的参数方程求曲面的面积“
- 171108 将Youtube自动翻译字幕转换成srt文件本地播放
- STM32的USART3(PC10,PC11)异常,USART3_TX(PC10)持续低电平(0V)
- 四川江安戏剧“青年训练营”:播撒颗颗戏剧种子
- 把撒哈拉沙漠变成一个太阳能农场,这可能吗?
- 微信windows版_微信多开教程:Win、Mac、iOS、Android
- 百度地图标注点+搜索
- 解决Google Colab 读取Google Drive(云盘) 文件速度慢