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工具的使用的更多相关文章

  1. 几个与JVM相关的JDK工具:jps, jstat, jmap

    在项目中遇到OOM(Out of Memory)的问题,为了分析内存和JVM的垃圾回收器GC问题,一并把JVM相关的一些工具也研究了一下: jps:Java进程查看工具,实际上它和Unix/Linux ...

  2. visualvm工具远程对linux服务器上的JVM虚拟机进行监控与调优

    文/朱季谦 最近在做了一些JVM监控与调优的事情,算是第一次实践,还比较陌生,故而先把这一次经验简单记下笔记,这样,对后面学习调优方面时,不至于又想不起来了.本文档主要总结在window本地环境远程对 ...

  3. JVM相关参数配置和问题诊断<转>

    原文连接:http://blog.csdn.net/chjttony/article/details/6240457 1.Websphere JVM相关问题诊断: 由JVM引起的Websphere问题 ...

  4. 3.1日 重温JVM相关信息

    1.JDK.JRE.JVM的关系: JDK是java开发的必备工具箱,JDK其中有一部分是JRE,JRE是JAVA运行环境,JVM则是JRE最核心的部分. 2.JVM的组成: JVM由4大部分组成:C ...

  5. JVM相关知识

    Java虚拟机学习分享最近主要在学习JVM相关知识,-知识主要来源<深入理解JAVA虚拟机>,深有感触,结合自己的理解,整理出一些经验,由于篇幅较长,就把链接帖出来,希望对大家有所帮助: ...

  6. 了解java虚拟机—JVM相关参数设置(2)

    1.   JVM相关参数设置 JVM相关配置 -XX:+PrintGC 两次次YoungGC,两次FullGC. -XX:+PrintGCDetails 打印GC时的内存,并且在程序结束时打印堆内存使 ...

  7. Java性能调优—— VisualVM工具基本使用及监控本地和远程JVM进程超详细使用教程

  8. jvm虚拟机性能监控与故障处理工具

    java开发人员肯定知道jdk的bin目录中有java.exe javac.exe这两个命令行工具,但并非所有程序员都了解过jdk的bin目录之中其他命令行的作用.jdk的工具,体积都比较小,这些命令 ...

  9. JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)

    性能分析工具jstatjmapjhatjstack 前提概要:         JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jsta ...

随机推荐

  1. UVA11019KMP(二维矩阵匹配出现次数)

    题意:     给你两个矩阵,一个大的一个小的,然后问你这个小矩阵在大的矩阵里出现了多少次? 思路:       说好了AC自动机的,我自己尝试写了个暴力的KMP竟然过了,AC自动机自己的模板还没写完 ...

  2. Docker用Commit给容器做快照

    关于 commit 镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础. 镜像是多层存储,每一层是在前一层的基础上进行修改:而容器同样也是多层存储,是在以镜像为 ...

  3. RSS阅读器 - Reeder

    苹果生态圈内最佳RSS阅读器 - Reeder 好用就完事了

  4. Thinking in UML 笔记(一) -- 面向对象

    一.UML 中最重要的就是面向对象. 面向对象的认识论可以构建更为复杂的系统来解释复杂的世界. 1. 面向过程,一切都是相互紧密地联系在一起,互相作用,互相影响. 2.面向对象, 世界是分割开的,只有 ...

  5. 如何使用java搭建一款高性能的Mqtt集群broker!

    SMQTT是一款开源的MQTT消息代理Broker, SMQTT基于Netty开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持 ...

  6. 【原创】JVM如何运行Java程序的?

    [Deerhang] 我们知道Java程序的运行是依赖于JVM虚拟机的,JVM类语言经过编译生成class字节码文件,字节码又经JVM进一步的编译生成机器码,最终运行在硬件上.那么JVM存在的意义是什 ...

  7. 如何利用CRM系统打通营销全渠道?

    企业经常通过不同渠道组织各种形式的营销推广,可惜,这些营销推广的效果往往差强人意. 相关研究表明,很多营销推广不理想的主要原因是不同营销渠道之间没有打通数据,不清楚每个营销渠道或营销策划的投入产出.推 ...

  8. rabbitmq介绍以及初步使用

    什么是MQ? ​ MQ(Message Queue):翻译为消息队列,通过典型的生产者和消费者模型,生产者不断向消息队列中生产消息,消费者不断地从队列中获取消息.因为消息的生产和消费都是异步的,而且只 ...

  9. LeetCode 617. 合并二叉树 Java

    给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 ...

  10. [bug] Hive:Caused by: MetaException(message:Hive Schema version 2.1.0 does not match metastore's schema version 1.2.0 Metastore is not upgraded or corrupt)

    参考 https://www.cnblogs.com/liupuLearning/p/6610307.html 少了创建hive数据库一步