jvm相关自我总结和 VisualVM工具的使用
idea 二个工具: jclasslib Hexview
jdk监控工具 VisualVM工具的使用: https://www.ibm.com/developerworks/cn/java/j-lo-visualvm/index.html
对象的创建过程?:
new--> 申请存储空间, 创建对象,此时对象处于半初始化状态
invokespecial #1 ---> 调用实例初始化方法,私有方法,父类构造方法
astore_1 ---> 将对象和栈中的局部变量建立联系
return -----> main函数跳出
DCL和volatile的问题, volatile不能少, 因为对象创建这个过程有可能出现指令重排, new--> invokespecial --> astore_1 这个过程 有可能会优化成 new --> astore_1 ---.invokespecial
这样会导致第一次判断实例是否为null, 此时对象处于半初始化状态,不为null, 从而返回, 破坏了单例模式
synchronized的底层原理:
java对象加了一个 synchronized 关键字
编译成字节码, 通过反编译可以看到 加了一个监视器 (monitorenter, monitorexit),
在jvm执行的过程中进行 锁升级,偏向锁--> 自旋锁 --->重量级锁
更底层的实现是: 汇编指令 lock comxchg
对象在内存中的存储布局: markword(8字节) class pointer(类型指针4字节,用于判断对象属于哪个类的实例), instance data(实例数据), padding(对其补充)
markword, class pointer 是对象头,对象头部markword的信息有:存储对象自身运行时数据, 锁信息, 对象分代年龄, hashcode,线程持有的锁, 偏向线程ID, 偏向时间戳
一个对象new出来, 此时是没有什么锁的, 当被 synchronized修饰,且只有一个线程来访问对象时候,此时, 会将这个线程id 标记到这个对象头(这就是偏向锁),这个线程一看是自己的线程id,就开始使用这个对象,
当有多个线程都来争抢这个对象时候,此时锁升级,升级为 自旋锁, 每个线程会在本线程内生成一个 lock record, 并都尝试将 这个lock record 添加到这个对象的markword中, 添加成功的线程开始使用这个对象, 添加失败的线程会在这里自旋(CAS) , 当这里自旋的线程变得很多的时候,会很消耗资源, jdk6之前是有个调优设置: 自旋的线程超过cpu核数一半,或者自旋次数超过10次, 就开始将自旋锁升级为 重量级锁, 现在的jdk8和之后版本中是有个 自适应机制,jvm自己来管理什么时候升级锁
重量级锁: 这里牵扯到二个概念: 用户态,内核态, 操作系统需要二种CPU状态, 内核态: 运行操作系统程序,操作硬件, 用户态: 运行用户程序, jvm执行代码,偏行锁和自旋锁处于用户态时候, 当锁升级为内核态时候, 向内核申请重量级锁, 重量级锁将所有自旋的线程放到一个队列中,排队执行,, 避免cpu空转
锁消除: 代码在JIT即时编译时,通过对上下文进行分析,去除掉没必要的加锁请求,比如一个方法中,new StringBuffer,之后不停的append, 由于这个StringBuffer对象只是在这个方法中使用,且append方法被synchronized修饰,如果不停的加锁,解锁,会消耗cpu资源, 所以jvm会将这里的锁消除
锁粗化: 代码在JIT即使编译时, 通过上下文分析,将多个锁合并为同一把锁,这样避免频繁加锁,解锁,而是共用同一把大锁, 比如一个方法中,new一个 stringBuffer while(true)代码块中,对这个buffer,append, jIT会优化: 将append的锁粗化,在while上面加一把锁
对象如何定位: 有二种方式: 句柄池, 直接指针(栈中引用直接指向堆中实例对象的内存地址)hotspot虚拟机使用的是直接指针
句柄池: 栈中引用指向堆中的句柄池,句柄池中保存了实例对象的内存地址和对象类型数据指针, 再通过句柄池中的地址间接找到堆中实例对象
对象如何分配: 此处有一个逃逸分析: 分析对象的作用域是否仅仅在某个方法中, 否则别的方法也引用这个对象,此时叫方法逃逸,如果某个对象是方法的返回值,别的线程会通过调用方法使用这个对象,此时叫线程逃逸,方法中的对象的作用域如果仅仅是在这个方法中, 直接将此对象分配到栈空间, 以便方法运行完毕,隧栈弹出而自动销毁 ,无需垃圾收集器收集
栈上分配失败,会尝试TLAB分配,(TLAB是eden区一部分,堆为每一个线程都分配一个 TLAB空间,用来分配对象,避免多个线程争夺同一块堆空间,TLAB空间小,很容易就满了,)之后就会将新对象,是否可以直接进入老年代,可以的话,就直接分配到老年代, 如果不可以,就会在eden区进行分配

new对象创建过程:
1: 检查这个对象对应的类是否加载 链接 初始化, 没有的话,就在双亲委派机制下 去加载这个类,
2: 为对象分配内存: 计算对象占用空间大小,在堆中划分一块内存给该对象, 划分内存这里有二种方式,如果堆内存空间不规则,虚拟机就维护一个列表,用来记录哪些内存是空闲的, 空闲列表方式. 另一种 指针碰撞,堆空间很规整, 使用过的内存在一边,未使用过的内存在一边,临界点是有一个指针, 这个指针移动对象空间大小即可, 到底使用哪种方法取决于所选择的垃圾收集器是否有压缩的能力决定
3: 处理并发安全问题: 多个对象创建争夺同一块内存区域引发并发安全问题, 解决: 使用 CAS+失败重试,保证原子性, 另一个方法是: TLAB(Thread Local Allocation Buffer) ,jvm为每一个线程在堆上都创建一小块区域内存空间 ,该线程创建对象,分配内存就从各自的TLAB的内存区域开始分配, 如果TLAB对应的内存区域不够用了,此时才会使用 CAS+失败重试
4: 初始化分配到的空间: 内存分配完成之后,对该对象对应的字段赋初始值, 字段类型对应的零值, 比如int: 0, long:0, String "", 这就是对象的半初始化
5: 设置对象的对象头: 设置对象头: 这个对象是哪个类的实例,怎样找到这个类的元数据 ,该对象的hash码,该对象的gc分代年龄(4字节,最大是15),等信息
6: 执行init方法进行初始化: 设置完对象头之后,从虚拟机角度看, 一个新对象已经产生了, 从java程序看 这个对象才刚开始创建,他的构造方法还没有执行, 所有的字段都是默认零值, 接下来执行init方法,
对象的内存布局:
对象头: 包含二部分: clazz pointer(类型指针, 虚拟机通过这个指针确定对象属于哪个类的实例) , mark world (运行时元数据), 有 哈希值, gc分代年龄, 锁状态标志, 线程持有的锁, 偏向锁ID 偏向时间戳, 如果该对象是数组还需要记录数组的长度
实例数据, 这里才是对象的真正存储的有效信息,即我们在程序代码中定义的各种类型的字段内容,无论是父类继承信息,还是子类定义的字段信息
对其填充: 任何对象的大小都必须是8字节的整数倍,不足就对其填充
对象的访问定位: 使用句柄, 直接指针
句柄: 堆中单独一块内存作为句柄池, 栈中的引用指向的是句柄池中 该对象对应的句柄地址, 句柄包含了该该对象对应实例数据, 类型数据信息
直接指针: 栈中的引用直接指向堆中该对象的实例数据, 实例数据中有该对象对应的类型数据信息地址
hotspot使用的是直接指针, 速度快,少了一次句柄池访问
jvm相关自我总结和 VisualVM工具的使用的更多相关文章
- 几个与JVM相关的JDK工具:jps, jstat, jmap
在项目中遇到OOM(Out of Memory)的问题,为了分析内存和JVM的垃圾回收器GC问题,一并把JVM相关的一些工具也研究了一下: jps:Java进程查看工具,实际上它和Unix/Linux ...
- visualvm工具远程对linux服务器上的JVM虚拟机进行监控与调优
文/朱季谦 最近在做了一些JVM监控与调优的事情,算是第一次实践,还比较陌生,故而先把这一次经验简单记下笔记,这样,对后面学习调优方面时,不至于又想不起来了.本文档主要总结在window本地环境远程对 ...
- JVM相关参数配置和问题诊断<转>
原文连接:http://blog.csdn.net/chjttony/article/details/6240457 1.Websphere JVM相关问题诊断: 由JVM引起的Websphere问题 ...
- 3.1日 重温JVM相关信息
1.JDK.JRE.JVM的关系: JDK是java开发的必备工具箱,JDK其中有一部分是JRE,JRE是JAVA运行环境,JVM则是JRE最核心的部分. 2.JVM的组成: JVM由4大部分组成:C ...
- JVM相关知识
Java虚拟机学习分享最近主要在学习JVM相关知识,-知识主要来源<深入理解JAVA虚拟机>,深有感触,结合自己的理解,整理出一些经验,由于篇幅较长,就把链接帖出来,希望对大家有所帮助: ...
- 了解java虚拟机—JVM相关参数设置(2)
1. JVM相关参数设置 JVM相关配置 -XX:+PrintGC 两次次YoungGC,两次FullGC. -XX:+PrintGCDetails 打印GC时的内存,并且在程序结束时打印堆内存使 ...
- Java性能调优—— VisualVM工具基本使用及监控本地和远程JVM进程超详细使用教程
- jvm虚拟机性能监控与故障处理工具
java开发人员肯定知道jdk的bin目录中有java.exe javac.exe这两个命令行工具,但并非所有程序员都了解过jdk的bin目录之中其他命令行的作用.jdk的工具,体积都比较小,这些命令 ...
- JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)
性能分析工具jstatjmapjhatjstack 前提概要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jsta ...
随机推荐
- hdu4302 set或者线段树
题意: 一条蛇生活在一个管子里,然后管子上面的某些位置会一次出现食物,每次蛇都会吃最近的食物,吃完之后就原地不动,等待下一次吃食物,如果有两个食物距离蛇一样远并且都是最近的,那么蛇不会掉头 ...
- XML / HTML / XHTML 的区别
目录 HTML XML XHTML HTML HTML(HyperText Markup Language):超文本标记语言,是一种用于创建网页的标准标记语言,是用来格式化并显示数据的 用HTML语法 ...
- 【python】Leetcode每日一题-旋转链表
[python]Leetcode每日一题-旋转链表 [题目描述] 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例1: 输入:head = [1,2,3,4,5] ...
- 自定义Tomcat部署目录
1.创建配置文件 在Tomcat安装目录中conf-->Catalina-->localhost目录下,创建项目访问请求路径.xml文件 内容如下: <Context path=&q ...
- 十进制转n进制
#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #defi ...
- Thinking in UML 笔记(一) -- 面向对象
一.UML 中最重要的就是面向对象. 面向对象的认识论可以构建更为复杂的系统来解释复杂的世界. 1. 面向过程,一切都是相互紧密地联系在一起,互相作用,互相影响. 2.面向对象, 世界是分割开的,只有 ...
- 制作一个简单的toast弹框
toast弹框的作用 toast弹框顾名思义,就是为了弹出一个提示框,效果如图: 使用toast弹框可以可用户带来更好的交互体验 toast弹框的使用 Toast组件 制做出toast的样式以及出现的 ...
- MySQL连接本地服务器
1.打开"控制面板" 2.搜索"管理工具",并点击第一个"管理工具" 3.双击"服务" 4.找到"MySQL& ...
- Azure Storage 利用 azCopy 复制迁移数据
一,引言 前两天遇到了Azure Blob Storage 需要迁移到另外的一个 Azure Blob Storage 中.手动下载.上传已经无法满足了,得另寻一种方式了 AzCopy.Azure 为 ...
- 【技术博客】使用iview的Tree组件写一棵文件树
本次项目的前端部分使用vue框架+iview组件构建,其中IDE的文件树部分使用了iview的Tree组件,但是Tree组件本身的接口功能极其有限,网上的相关资料也不多,在使用时费了一番功夫才摸索清楚 ...