莱芜网站建设电话,wordpress旅行社,怎么进电力建设公司网站,网站创建域名【0】README 0.1#xff09;本文转自 深入理解jvm#xff0c; 旨在学习 java内存区域 的基础知识#xff1b; 【1】运行时数据区域 1#xff09;jvm 所管理的内存将会包括以下几个运行时数据区域 1.1#xff09;方法区#xff1b;#xff08;线程共享#xff09; 1.2本文转自 深入理解jvm 旨在学习 java内存区域 的基础知识 【1】运行时数据区域 1jvm 所管理的内存将会包括以下几个运行时数据区域 1.1方法区线程共享 1.2虚拟机栈线程私有 1.3本地方法栈线程私有 1.4java 堆线程共享 1.5程序计数器线程私有 Attention 除了程序计数器外虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError内存溢出 异常的可能 【1.1】程序计数器线程私有 1程序计数器 是一块较小的内存空间可以看做是当前线程所执行的字节码的行号指示器干货——程序计数器行号指示器 2其作用 为了线程切换后能恢复到正确的执行位置每条线程都需要有一个独立的程序计数器各条线程之间计数器互不影响独立存储我们称这类内存区域为“线程私有”的内存 3此内存区域是唯一一个在 jvm 规范中 没有规定任何 OutOfMemoryError 情况的区域 【1.2】java 虚拟机栈线程私有用于存储局部变量表操作数栈动态链接方法出口等信息 1虚拟机栈的作用 描述的是 java 方法执行的内存模型每个方法在执行的时候都会创建一个栈帧用于存储局部变量表操作数栈动态链接方法出口等信息 2局部变量表 存放了编译器可知的基本数据类型对象引用 和 return address 类型指向了一跳字节码指令的地址 3局部变量空间Slot 其中64 位长度的long 和 double 类型数据都会占用两个局部变量空间slot其余的数据类型占用1个干货——引入slot局部变量空间 4jvm 在该区域规定了两种异常 Exception1如果线程请求的栈深度大于jvm 所允许的深度将抛出 StackOverFlowError 异常 Exception2如果虚拟机栈可以动态扩展如果扩展时无法申请到足够的内存就会抛出 OutOfMemoryError 异常 【1.3】本地方法栈线程私有 1本地方法栈的作用于 虚拟机栈的作用相似 2他们作用的区别在于 虚拟机栈为虚拟机执行 java字节码服务而本地方法栈为 虚拟机使用到的 Native 方法本地方法服务 【1.4】java 堆存放对象实例线程共有 1java 堆的唯一作用存放对象实例几乎所有的对象实例都在这里分配内存 2GC堆垃圾收集堆 java 堆是垃圾收集器管理的主要区域因此很多时候也被称为 GC堆Garbage Collected Heap 3从内存回收的角度看由于现在收集器基本都采用分代收集算法所以 java 堆还可以分为 新生代 和 老年代干货——在java堆中引入新生代和老年代 4从内存分配的角度来看线程共享的 java 堆可能划分出多个线程私有的分配缓冲区Thread Local Allocation Buffer, TLAB 5java堆 可以处理物理上不连续的内存空间中 只要逻辑上是连续的即可 6 java 堆是可扩展的不过当前主流的jvm 都是按照可扩展来实现的通过 Xmx 和 -Xms 控制 如果在堆中没有内存完成实例分配并且堆也无法再扩展将会抛出 OutOfMemoryError 异常 【1.5】方法区用于存放 class 的相关信息线程共有 1方法区的作用用于存储被虚拟机加载的类信息常量静态变量即时编译器JIT编译后的代码等数据 2方法区除了和 java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外还可以选择不实现垃圾收集 3 方法区的内存回收目标 主要是针对常量池的回收和对类型的卸载 【1.6】运行时常量池 1运行时常量池是方法区的一部分 2Class 文件中除了有类的版本字段方法接口等描述信息外还有一个信息——常量池干货——引入常量池 3常量池的作用用于存放编译器生成的各种字面量和符号引用这部分内容将在类加载后进入方法区的运行时常量池中存放 运行时常量池的一个重要特征具备动态性干货——运行时常量池的具备动态性 看个荔枝 并非预置入 Class 文件中常量池的内容才能进入方法区运行时常量池运行期间也可能将新的常量放入池中 这种特性被开发人员利用的多的便是 String类的 intern 方法 【1.7】直接内存 0直接内存 分配在本机直接内存上不是 jvm 运行时数据区的一部分但被频繁地使用 1jdk1.4 中新加入了NIOnew input/output类 引入了一种基于通道与缓冲区buffer的IO方式他可以使用 Native 函数库直接分配堆外内存然后通过一个存储在java 堆中的DirectByteBuffer 对象作为这块内存的引用进行操作这样能在一些场景中提高性能因为避免了在 java 堆 和 Native 堆中来回复制数据 2显然本机直接内存的分配不会受到 java 堆大小的限制 【2】HotSpot 虚拟机对象探秘 1对象的创建steps step1是否执行类加载过程虚拟机遇到一条new指令首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用并且检查这个符号引用代表的类是否已被加载解析和初始化过。如果没有那必须执行相应的类加载过程 step2分配内存 接下来 虚拟机将为新生对象分配内存。内存分配方式有 指针碰撞 和 空闲列表 problem对象创建在虚拟机中是非常频繁的行为即使是仅仅修改一个指针指向的位置 在并发情况下也并不是线程安全的。如可能出现正在给对象A分配内存指针还未来得及修改对象B 又同时使用了原来指针来分配内存的情况 solution1对分配内存空间的动作进行同步处理——实际上采用 CAS 配上失败重试的方式保证更新操作的原子性 solution2吧内存分配的动作按照线程划分在不同的空间中进行即每个线程在 java堆中预先分配一小块内存称为本地线程分配缓冲Thread Local Allocation BufferTLAB只有TLAB用完并分配新的TLAB时才需要同步锁定干货——每个线程在 java堆中预先分配一小块内存称为本地线程分配缓冲 step3初始化为零 内存分配完成后虚拟机需要将分配到 的内存空间都初始化为零值 step4虚拟机对对象进行必要的设置 如这个对象的类是什么如果才能找到类的元数据信息对象的哈希码对象的GC 分代年龄等信息。这些信息存放在对象的对象头中干货——引入了对象头 step5执行 init方法 执行完new 执行后会执行 init 方法把对象按照程序员的意愿进行初始化 【2.1】对象的内存布局 1对象的内存布局分为3个区域 对象头 实例数据 和 对齐填充 2HotSpot 虚拟机的对象头包括两部分数据 2.1对象头第一部分Mark Word用于存储对象自身的运行时数据如哈希码GC分代年龄锁状态标志线程持有的锁偏向线程ID偏向时间戳这部分数据的长度在 32位 和 64 位的虚拟机未开启压缩指针中分别为 32bit 和 64 bit 官方称为 “Mark Word”干货——引入对象头的Mark Word对象头信息是与对象自身定义 的数据无关的额外存储成本考虑到虚拟机的空间效率Mark Word被设计成 非固定的数据结构以便在 极小的空间内存储尽量多的信息干货——对象头信息是与对象自身定义 的数据无关的额外存储成本 ComplementaryHotSpot 虚拟机对象头 Mark Word2.2对象头第二部分类型指针类型指针 即对象指向它的类元数据的指针虚拟机通过这个指针来确定这个对象是哪个类的实例 3对象的实例数据区域是对象真正存储的有效信息也是在程序代码中所定义的各种类型的字段内容 4对象的对齐填充区域 没有什么特别的含义它仅仅起着占位符的作用 换句话说就是对象的大小必须是 8字节 的整数倍 【2.3】对象的访问定位 1java 程序需要通过 栈上的 引用数据来操作堆上的具体对象。 2引用应该通过何种方式去定位访问堆中的对象的具体位置目前主流的访问方式有 使用句柄 和 直接指针两种干货——栈上引用访问堆上对象的主流访问方式 2.1使用句柄访问方式 那么java 堆中将会划分出一块内存来作为句柄池引用数据中存储的就是对象的句柄地址而句柄地址包含了对象实例数据和类型数据各自的具体地址 2.2使用直接指针访问Sun HotSpot 使用这种方式访问