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.内存结构的更多相关文章

  1. 巩固java(二)----JVM堆内存结构及垃圾回收机制

    前言:        我们在运行程序时,有时会碰到内存溢出(OutOfMemoryError)的问题,为了解决这种问题,我们有必要了解JVM的内存结构和垃圾回收机制. 正文: 1.JVM堆内存结构   ...

  2. JVM的内存结构,JVM的回收机制

    内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收 ...

  3. JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)

    一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...

  4. JVM之内存结构详解

    对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.今天开始,<JVM详解>系列开启,带大家深入了解JVM相 ...

  5. JVM的内存结构以及性能调优

    JVM的内存结构以及性能调优 发布时间: 2017-11-22 阅读数: 16675 JVM的内存结构以及性能调优1:JVM的结构主要包括三部分,堆,栈,非堆内存(方法区,驻留字符串)堆上面存储的是引 ...

  6. JVM的基本结构和JVM的内存结构

    这里概要介绍一下JVM在启动后,作为操作系统的一个进程的基本结构,以及从操作系统角度看,JVM如何管理它从操作系统里申请来的内存的,也就是JVM的内存结构或者叫JVM内存模型. 1.JVM的基本结构 ...

  7. JVM:内存结构

    JVM:内存结构 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 P ...

  8. JVM之内存结构

    JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...

  9. Java中的JVM的内存结构

    Java的虚拟机自身结构图: JVM内存结构主要包括两个子系统和两个组件.两个子系统分别是Classloader子系统和Executionengine(执行引擎)子系统:两个组件分别是Runtimed ...

  10. JVM(一) 内存结构

    JVM内存结构 方法区(JDK8以上叫元空间)和堆为线程共享区,虚拟机栈.本地方法栈及程序计数器为线程独占区,  还有一个没有在下图中体现的叫做直接内存(Direct Memory),不受JVM GC ...

随机推荐

  1. centos更改java的环境变量

    vi  /etc/profile 在最后添加这个信息,或修改这些信息 export JAVA_HOME=/usr/local/java/jdk1.8.0_251export CLASSPATH=.:$ ...

  2. [Oracle19C 数据库管理] 加载和传输数据库

    移动数据的通用架构 数据泵data pump(impdp, expdp),借助DBMS_DATAPUMP存储过程,可以进行表的导出导入,行记录的导出导入,表空间的导出导入或者整个schema的导出导入 ...

  3. EXCEL函数总结

    ------------------截取"号"之前的字符 =MID(A45,1,FIND("号",A45,1)-1)

  4. 【Python】变量&数据类型&运算符

    一.Python变量&数据类型&运算符 1.print()函数 1.1 输出数字,字符串,含有运算符的表达式 print(123) print('hello world') print ...

  5. django查询中values_list(flat=True) 是什么意思?

    1.values() departments = models.Department.objects.filter(dpm_status=1).values('dnp__name') print(de ...

  6. view 相关代码片段笔记

    代码中动态创建view,并把AttributeSet加入到当前自定义的view中,动态创建属性相关 //https://blog.csdn.net/chenhuakang/article/detail ...

  7. CF1067E 题解

    题意 传送门 给定一棵 \(n\) 个节点的树,每条边有 \(\frac{1}{2}\) 的概率出现,可以得到一个森林,求这个森林邻接矩阵的秩的期望. \(1\le n\le5\times10^5\) ...

  8. 整理15款实用javascript富文本编辑器

    百度UEditor 官方网址:http://ueditor.baidu.com/website/ UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验 ...

  9. 软件离线许可(License)实现原理

    我们经常使用各种开发软件,比如IntelliJ IDEA.Navicat.Visual Studio等,这些软件都有一个特点,就是要收费.一般是我们需要去购买一个许可,然后输入这个许可到软件里就能够使 ...

  10. 寻找进程ID