JVM - 1.内存结构
1 内存结构
1.1 程序计数器
1.1.1 作用
在执行的过程中 , 记住下一条jvm指令的执行地址
物理上通过寄存器实现
1.1.2 特性
每个线程都有自己的程序计数器 - 线程私有
不会存在内存溢出
1.2 虚拟机栈
1.2.1 定义
栈 - 线程运行需要的内存空间
栈帧 - 每个方法运行时所需要的内存
- 方法执行时,方法所用的栈帧入栈
- 方法执行完成时 , 栈帧出栈(内存被释放) jvm内存回收机制
每个线程运行时 只能有一个 活动栈帧
1.2.3 一些相关问题
栈内存不需要进行垃圾回收(后面所提及的堆内存需要)
默认栈大小 - 1024kb
widows根据虚拟内存所分配
如果方法内的局部变量没有逃离方法分作用访问, 它是线程安全的
如果局部变量引用了对象 , 并逃离了作用范围需要考虑线程安全问题
1.2.3 栈内存溢出
栈帧过多导致的栈内存溢出
此处无限递归,造成栈帧过多 , 内存溢出 , 抛出异常StackOverFlowError
更改栈帧大小的操作
重新更改栈大小 VM options 添加 -Xss256k , 此时循环次数降低就造成了栈溢出
栈帧过大造成的栈内存溢出
如果两个类相互套娃, 都有对方的作为成员变量 , 那么在转换成json时会无限转换下去,直至栈溢出
1.2.4 线程运行诊断
cpu占用过多 - 定位
哪个进程占用资源更高
运行jar 用top命令进行检测
查询到了进程所使用的资源
哪个线程占用过高
用 ps H -eo pid,tid,%cpu 命令
查询线程所占用的资源
jstack 工具列出所有java线程
线程id需要转换成十六进制
进一步定位到问题源代码的行号
程序运行很长时间没有结果
有可能是发生了死锁
用jstack查看进程
1.3 本地方法栈
在与更底层的功能交互时,需要调用用c或者其他偏向底层的语言写的本地方法接口 , 关键词 native 此时会给调用的本地方法提供一定的内存空间
1.4 堆
1.4.1 定义
通过new关键字创建对象时都会使用堆内存
- 特点
他是线程共享的 , 堆中的对象都需要考虑线程安全的问题
有垃圾回收机制
1.4.2 堆内存溢出
更改堆大小 - 默认4GB
-Xmx8m
1.4.3 堆内存诊断
工具:
jvisualvm工具 - 可视化 , 能够保存当前堆的快照进行分析
1.5 JVM方法区
1.5.1 概念
jdk 1.6 - 用永久代(PermGen) 实现 用堆内存存储
存储着:常量池(包含StringTable) Class ClasLoader
1.8 Metaspace 元空间 实现 存储在本地内存中
存储着:常量池 Class ClasLoader
StringTable 仍然存储在堆中
1.5.2 方法区内存溢出
元空间的内存溢出
永久代的内存溢出
1.5.3 运行时常量池
java -v xx.class 反编译类 输出类编译后的信息
二进制字节码 : 类基本信息 , 常量池, 类方法定义, 包含了虚拟机指令
- 常量池:就是一张表 , 虚拟机根据这张常量表找到要执行的类名 方法名 参数类型
字面量等信息
- 运行时常量池 , 常量池是 *.class 文件中的,当该类被加载, 他的常量池信息就好被放入运行时常量池,并把里面的符号地址变为真实地址
1.5.3 StringTable
ldc #2 --- 会把a符号变成“a”字符串对象 放入常量池中(先会在常量池的哈希表结构中查找,如果没那就放进去,如果存在,那么就会将地址指向它)
string s4 = s1 + s2;
两个字符串拼接 - 会先创建个StringBuilder对象 然后调用append方法拼接 最后调用tostring tostring 是new出一个string 所以存放在堆中
string s5 = "a" + "b";
javac在编译期优化 , 两个常量拼接在编译期间就确定了,所以直接加入串池
s.intern()
将该字符串对象尝试放入串池中 如果有则不会放入 如果没有则放入串池
将串池的对象返回
jdk1.6会将对象拷贝一份再放入串池
1.8 直接将该对象放入串池
1.5.4 永久代、新生代、老年代(插入)
参考博客:https://blog.csdn.net/zs18753479279/article/details/119341774
概念:
Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。
堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。而新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。
- 新生代中一般保存新出现的对象,所以每次垃圾收集时都发现大批对象死去,只有少量对象存活,便采用了复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
- 老年代中一般保存存活了很久的对象,他们存活率高、没有额外空间对它进行分配担保,就必须采用“标记-清理”或者“标记-整理”算法。
- 永久代就是JVM的方法区。在这里都是放着一些被虚拟机加载的类信息,静态变量,常量等数据。这个区中的东西比老年代和新生代更不容易回收。
1.5.5 StringTable 垃圾回收
打印垃圾回收信息
1.5.6 StringTable性能调优
常量较多的情况下,增加哈希桶的数量 , 以此来减少哈希碰撞的概率,进而提高了效率(以空间换时间)
-XX:StringTableSize=桶个数
将常用的变量入池 , 比不入池的内存占用较小
s.intern()
1.6 直接内存
1.6.1 定义
ByteBuffer.allocateDirect(1024*1024);
提高大文件的读写性能
正常的文件读写
CPU从用户态转换到内核态 再转换到用户态
文件的读写从磁盘文件读入到系统内存中的系统缓存区 而后读入java的缓冲区 磁盘效率低
使用了direct memory 从系统内存中划出一个缓冲区 , java和系统都能够直接访问它
少了一次缓冲区的复制操作 效率大大提高
1.6.2 释放原理
直接内存的内存管理并不是由jvm的内存机制管理的 ,内置的垃圾回收对象对它无效,这里是使用Unsafe来释放内存的
unsafe.freeMemory(地址[long]) unsafe对象可以通过暴力反射来获取
因为bytebuff对象被回收 虚引用机制的关联 使得Unsafe触发回收了直接内存
ByteBuffger的实现类内部 , 使用了Cleaner(虚引用)来监测ByteBuffer对象 , 一单ByteBuffer对象被垃圾回收 , 那么就会由ReferenceHandler线程通过Cleaner 的 clean方法调用freeMemory来直接释放内存
-XX:+DisableExplicitGC 禁用显式的垃圾回收 , jvm调优时加上, 显示垃圾回收时不会Full GC
System.gc() // 显式的垃圾回收 Full GC
但是这样会引发问题 , 如果使用直接内存时, 显示回收没法回收掉byteBuffer的对象 , 造成直接内存没法及时释放,只有等到系统触发垃圾回收时才能一起释放掉
这就需要我们自己去暴力反射获取unsafe , 从而手动的释放直接内存
JVM - 1.内存结构的更多相关文章
- 巩固java(二)----JVM堆内存结构及垃圾回收机制
前言: 我们在运行程序时,有时会碰到内存溢出(OutOfMemoryError)的问题,为了解决这种问题,我们有必要了解JVM的内存结构和垃圾回收机制. 正文: 1.JVM堆内存结构 ...
- JVM的内存结构,JVM的回收机制
内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收 ...
- JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)
一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...
- JVM之内存结构详解
对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.今天开始,<JVM详解>系列开启,带大家深入了解JVM相 ...
- JVM的内存结构以及性能调优
JVM的内存结构以及性能调优 发布时间: 2017-11-22 阅读数: 16675 JVM的内存结构以及性能调优1:JVM的结构主要包括三部分,堆,栈,非堆内存(方法区,驻留字符串)堆上面存储的是引 ...
- JVM的基本结构和JVM的内存结构
这里概要介绍一下JVM在启动后,作为操作系统的一个进程的基本结构,以及从操作系统角度看,JVM如何管理它从操作系统里申请来的内存的,也就是JVM的内存结构或者叫JVM内存模型. 1.JVM的基本结构 ...
- JVM:内存结构
JVM:内存结构 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 P ...
- JVM之内存结构
JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...
- Java中的JVM的内存结构
Java的虚拟机自身结构图: JVM内存结构主要包括两个子系统和两个组件.两个子系统分别是Classloader子系统和Executionengine(执行引擎)子系统:两个组件分别是Runtimed ...
- JVM(一) 内存结构
JVM内存结构 方法区(JDK8以上叫元空间)和堆为线程共享区,虚拟机栈.本地方法栈及程序计数器为线程独占区, 还有一个没有在下图中体现的叫做直接内存(Direct Memory),不受JVM GC ...
随机推荐
- centos更改java的环境变量
vi /etc/profile 在最后添加这个信息,或修改这些信息 export JAVA_HOME=/usr/local/java/jdk1.8.0_251export CLASSPATH=.:$ ...
- [Oracle19C 数据库管理] 加载和传输数据库
移动数据的通用架构 数据泵data pump(impdp, expdp),借助DBMS_DATAPUMP存储过程,可以进行表的导出导入,行记录的导出导入,表空间的导出导入或者整个schema的导出导入 ...
- EXCEL函数总结
------------------截取"号"之前的字符 =MID(A45,1,FIND("号",A45,1)-1)
- 【Python】变量&数据类型&运算符
一.Python变量&数据类型&运算符 1.print()函数 1.1 输出数字,字符串,含有运算符的表达式 print(123) print('hello world') print ...
- django查询中values_list(flat=True) 是什么意思?
1.values() departments = models.Department.objects.filter(dpm_status=1).values('dnp__name') print(de ...
- view 相关代码片段笔记
代码中动态创建view,并把AttributeSet加入到当前自定义的view中,动态创建属性相关 //https://blog.csdn.net/chenhuakang/article/detail ...
- CF1067E 题解
题意 传送门 给定一棵 \(n\) 个节点的树,每条边有 \(\frac{1}{2}\) 的概率出现,可以得到一个森林,求这个森林邻接矩阵的秩的期望. \(1\le n\le5\times10^5\) ...
- 整理15款实用javascript富文本编辑器
百度UEditor 官方网址:http://ueditor.baidu.com/website/ UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验 ...
- 软件离线许可(License)实现原理
我们经常使用各种开发软件,比如IntelliJ IDEA.Navicat.Visual Studio等,这些软件都有一个特点,就是要收费.一般是我们需要去购买一个许可,然后输入这个许可到软件里就能够使 ...
- 寻找进程ID