Klass

JVM内存结构、 Java内存模型、 Java对象模型

为君一笑 提交于 2020-04-26 08:35:45
Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的 JVM内存结构 、 Java内存模型 和 Java对象模型 ,这就是 三个截然不同的概念 ,但是很多人容易弄混。 可以这样说,很多高级开发甚至都搞不不清楚JVM内存结构、Java内存模型和Java对象模型这三者的概念及其间的区别。甚至我见过有些面试官自己也搞的不是太清楚。不信的话,你去网上搜索Java内存模型,还会有很多文章的内容其实介绍的是JVM内存结构。 首先,这三个概念是完全不同的三个概念。 本文主要对这三个概念加以区分以及简单介绍。其中每一个知识点都可以单独写一篇文章,本文并不会深入介绍,感兴趣的朋友可以加入我的知识星球和球友们共同学习。 JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《 Java虚拟机规范(Java SE 8) 》中描述了JVM运行时内存区域结构如下: 各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点: 1、以上是Java虚拟机规范,不同的虚拟机实现会各有不同

Java内存模型、JVM内存结构和Java对象模型

别来无恙 提交于 2020-04-26 08:35:14
JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《 Java虚拟机规范(Java SE 8) 》中描述了JVM运行时内存区域结构如下: 各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点: 1、以上是Java虚拟机规范,不同的虚拟机实现会各有不同,但是一般会遵守规范。 2、规范中定义的方法区,只是一种概念上的区域,并说明了其应该具有什么功能。但是并没有规定这个区域到底应该处于何处。所以,对于不同的虚拟机实现来说,是由一定的自由度的。 3、不同版本的方法区所处位置不同,上图中划分的是逻辑区域,并不是绝对意义上的物理区域。因为某些版本的JDK中方法区其实是在堆中实现的。 4、运行时常量池用于存放编译期生成的各种字面量和符号应用。但是,Java语言并不要求常量只有在编译期才能产生。比如在运行期, String.intern 也会把新的常量放入池中。 5、除了以上介绍的JVM运行时内存外,还有一块内存区域可供使用,那就是 直接内存 。Java虚拟机规范并没有定义这块内存区域,所以他并不由JVM管理,是利用本地方法库直接在堆外申请的内存区域。 6

曹工杂谈:Java 类加载还会死锁?这是什么情况?

浪子不回头ぞ 提交于 2020-04-25 09:53:57
一、前言 今天事不是很多,正好在Java交流群里,看到一个比较有意思的问题,于是花了点时间研究了一下,这里做个简单的分享。 先贴一份测试代码,大家可以先猜测一下,执行结果会是怎样的: 2 3 import java.util.concurrent.TimeUnit; 4 5 6 public class TestClassLoading { 7 public static class A{ 8 static { 9 System.out.println("class A init" ); 10 try { 11 TimeUnit.SECONDS.sleep(1 ); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 new B(); 16 } 17 18 public static void test() { 19 System.out.println("aaa" ); 20 } 21 } 22 23 public static class B{ 24 static { 25 System.out.println("class B init" ); 26 new A(); 27 } 28 29 30 public static void test() { 31 System.out

你写的Java对象究竟占多少内存?

跟風遠走 提交于 2020-03-26 11:36:53
3 月,跳不动了?>>> Java 作为一个面向对象语言,给我们带来了多态,继承,封装等特性,使得我们可以利用这些特性很轻松的就能构建出易于扩展,易于维护的代码。 作为一个Javaer,天天搞“对象”,那你写的对象究竟占用了多少内存呢? 我们来看看你的“对象”是如何“败家”的。 本文环境:jdk1.8_64 Java 对象头内存模型 我们先来看看,一个Java 对象的内存模型是怎么样的? 由于我们的虚拟机是分为32位和64位,那肯定它们的模型也是有区别的,下面我列出列32位虚拟机和64位虚拟机下的Java对象头内存模型。 因为笔者的本地环境是jdk1.8,64位虚拟机,这里我以64位虚拟机(开启指针压缩)来分析,因为默认情况下,jdk1.8 在64位虚拟机默认开启指针压缩。 Java 对象头主要包括两部分,第一部分就是 Mark Word,这也是 Java 锁实现原理中重要的一环,另外一部分是 Klass Word。 Klass Word 这里其实是虚拟机设计的一个oop-klass model模型,这里的OOP是指Ordinary Object Pointer(普通对象指针),看起来像个指针实际上是藏在指针里的对象。而 klass 则包含 元数据和方法信息,用来描述 Java 类。它在64位虚拟机开启压缩指针的环境下占用 32bits 空间。 Mark Word 是我们分析的重点

Metaspace

耗尽温柔 提交于 2020-03-10 19:58:03
一、从方法区(PermGen)到元空间(Metaspace) 方法区(PermGen) JDK1.8以前的HotSpot JVM有 方法区 ,也叫 永久代(permanent generation) 。 方法区用于存放已被虚拟机加载的 类信息、常量、静态变量,即编译器编译后的代码 。 方法区是一片 连续的堆空间 ,通过 -XX:MaxPermSize 来设定永久代最大可分配空间,当JVM加载的类信息容量超过了这个值,会报 OOM:PermGen 错误。 永久代的 GC 是和老年代(old generation)捆绑在一起的,无论谁满了,都会触发永久代和老年代的垃圾收集。 JDK1.7开始了方法区的部分移除: 符号引用(Symbols) 移至 native heap , 字面量(interned strings) 和 静态变量(class statics) 移至 java heap。 为什么要用Metaspace替代方法区 随着动态类加载的情况越来越多,这块内存变得不太可控,如果设置小了,系统运行过程中就容易出现内存溢出,设置大了又浪费内存。 二、Metaspace的组成 Metaspace由两大部分组成:Klass Metaspace和NoKlass Metaspace。 Klass Metaspace Klass Metaspace就是用来存 klass 的

JDK之JVM中Java对象的头部占多少byte

会有一股神秘感。 提交于 2020-03-01 12:28:31
先做个铺垫: 在32位机器上word size是32bits,CPU一次性处理32bits,在64位机器上word size是64bits,CPU一次性处理64bits。 Data bus size, instruction size, address size are usually multiples of the word size,这句参考自 Stackoverflow 。 1. Stackoverflow上看到的Java对象头部mark word和kclass pointer的大小 从Stackoverflow上 看到,Java对象头部有一个 mark word 和一个 klass pointer, mark word:32bits architectures上,mark word占32bits,64bits architectures上,mark word占64bits; kclass pointer:32bits architectures上,kclass pointer占32bits,64bits architectures上,kclass pointer占64bits,但也可能是32bits,原话是这样"the klass pointer has word size on 32 bit architectures. On 64 bit architectures

深入浅出,Handler机制外科手术式的剖析(ThreadLocal,Looper,MessageQueen,Message)(下)

喜欢而已 提交于 2020-03-01 02:31:44
深入浅出,Handler机制外科手术式的剖析(ThreadLocal,Looper,MessageQueen,Message)(上) 此文是Handler机制的第二篇,第一篇没有看的小伙伴,可以戳上边看一看哟。 上一篇我们对ThreadLocal和Looper进行了剖析,接着上篇,讲讲MessageQueen和Handler类。 MessageQueen和Message MessageQueen是存放Message的,翻译过来叫消息队列,但是它内部并不是一个消息队列,而是一个单链表的数据结构,里边存放的数据就是Message。MessageQueen中的mMseeages字段存放的是头节点。既然是链表,就一定会涉及到插入和取出,我们先看下它的插入方法: boolean enqueueMessage(Message msg, long when) { synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; }

JVM源码分析之Metaspace解密

℡╲_俬逩灬. 提交于 2020-02-27 20:50:22
概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所致,看到大家讨论来讨论去,看得出很多人对metaspace还是模棱两可,不是很了解它,因此我觉得有必要写篇文章来介绍一下它,解开它神秘的面纱,当我们再次碰到它的相关问题的时候不会再感到束手无策。 通过这篇文章,你将可以了解到 为什么会有metaspace metaspace的组成 metaspace的VM参数 jstat里我们应该关注metaspace的哪些值 为什么会有metaspace metaspace的由来民间已有很多传说,不过我这里只谈我自己的理解,因为我不是oracle参与这块的开发者,所以对其真正的由来不怎么了解。 我们都知道jdk8之前有perm这一整块内存来存klass等信息,我们的参数里也必不可少地会配置-XX:PermSize以及-XX:MaxPermSize来控制这块内存的大小,jvm在启动的时候会根据这些配置来分配一块连续的内存块,但是随着动态类加载的情况越来越多,这块内存我们变得不太可控,到底设置多大合适是每个开发者要考虑的问题,如果设置太小了,系统运行过程中就容易出现内存溢出,设置大了又总感觉浪费,尽管不会实质分配这么大的物理内存。基于这么一个可能的原因

HotSpot和OpenJDK入门

故事扮演 提交于 2020-02-27 01:56:34
在本文中,我们将会介绍如何开始使用HotSpot Java 虚拟机以及它在OpenJDK开源项目中的实现——我们将会从两个方面进行介绍,分别是虚拟机和虚拟机与Java类库的交互。 HotSpot源码介绍 首先让我们看看JDK源码和它所包含的相关Java概念的实现。检查源码的方式主要有两种: 现代IDE能够附加src.zip(在$JAVA_HOME目录),能够从IDE中访问 使用OpenJDK的源码并导航到文件系统 这两种方式都非常有用,但是重要的是哪种方式比较舒适一点。OpenJDK的源码存储在Mercurial(一个分布式的 版本控制 系统,与流行的 Git 版本控制系统相似)中。如果你不熟悉Mercurial,可以查看这本名为“ 版本控制示例 ”的免费书,该书介绍了相关的基础内容。 为了检出OpenJDK 7的源码,你需要安装Mercurial命令行工具,然后执行以下命令: hg clone http://hg.openjdk.java.net/jdk7/jdk7 jdk7_tl 该命令会在本地生成一个OpenJDK仓库的副本。该仓库含有项目的基础布局,但是并没有包含所有的文件——因为OpenJDK项目分别分布在几个子仓库中。 完成克隆之后,本地仓库应该有类似于下面的内容: ariel-2:jdk7_tl boxcat$ ls -l total 664 -rw-r--r-- 1

面试【JAVA基础】锁

ε祈祈猫儿з 提交于 2019-12-18 23:41:06
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 1、锁状态 锁的状态只能升级不能降级。 无锁 没有锁对资源进行锁定,所有线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。其他修改失败的线程会不断重试,直到修改成功,如CAS原理和应用是无锁的实现。 偏向锁 偏向锁是指一段同步代码一直被一个线程访问,那个该线程会自动获取锁,降低获取锁的代价。 轻量级锁 是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。通过cas操作和自旋来解决加锁问题,自旋超过一定的次数或者已经有一个线程在自旋,又来一个线程获取锁时,轻量级锁会升级为重量级锁。 重量级锁 升级为重量级锁,等待锁的线程都会进入阻塞状态。 2、乐观锁与悲观锁 乐观锁,每次拿数据的时候认为别人都不会修改,在更新的时候再判断在此期间有没有更新数据,可以使用版本号等机制,适合读取多场景,提高性能。 悲观锁,每次拿数据都认为别人会修改,都会上锁,可以使用synchronized、独占锁Lock、读写锁等机制,适合写多的场景,保证写入操作正确。 3、自旋锁与适应性自旋锁 自旋锁:指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断判断锁是否能获取成功,直到获取到锁才退出循环。 优点:线程不进行上下文切换