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. jmeter 添加断言和查看断言结果

    在对应的请求下添加响应断言,这里我们添加响应文本来作为检查点,来检查上面的这个请求是否成功 断言和断言结果是成对出现的,是为了检查我们添加的断言是否验证成功,如下图,如果成功,里面就会有对应的结果,且 ...

  2. 【Tomcat】ubuntu系统安装Tomcat

    Tomcat简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,支持最新的Servlet 2.4 和JSP 2.0 规范,在中小型系统和并发访问用户不是很多的场 ...

  3. ORACLE之自治事务

    在创建存储过程时,可以用关键字: PRAGMA AUTONOMOUS_TRANSACTION 创建自治事务. 常用场景: 触发器抛错导致事务回滚,日志的记录需要用自治事务进行记录 代码抛错,导致数据库 ...

  4. shopt 内置命令启用shell选项 (extglob)

    使用shopt 内置命令启用shell选项 (extglob) 则会识别几个扩展模式匹配运算符 模式列表是由 | 分割 查看shell选项 extglob shopt |grep extglob 启动 ...

  5. C# 调用c库

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runti ...

  6. python pip 换源

    title: pip 换源 author: 杨晓东 permalink: pip-换源 date: 2021-10-02 11:27:04 categories: - 投篮 tags: - demo ...

  7. C++实现单链表相关操作

    #include<iostream>#include<cstdlib>//C++动态分配存储空间using namespace std;#define OK 1#define ...

  8. Java流程控制之while循环详解

    while循环 while循环 do...while循环 for循环 在Java5中引入了一种主要用于数组的增强型for循环 while循环 while循环是最基本的循环,它的结构为 while(布尔 ...

  9. Window:下载并安装FileZilla客户端

    FileZilla官方网站:https://filezilla-project.org/ 环境 操作系统:Window 10 企业版LTSC;内存:8GB;操作类型:64位. 说明 本人想在腾讯云的系 ...

  10. 第八章 mysql的主从复制

    mysql的主从复制 一 主从复制搭建 1. 准备三台主机  (这个是多实例) 3307 master3308 salve13309 salve2 2. master 节点设置 [mysqld] lo ...