虚拟机 java 开发_深入浅出 Java 虚拟机 · 通往高级 Java 开发的必经之路

第一章 JVM 内存模型

Java 虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是:程序计数器

Java 虚拟机栈

本地方法栈

方法区。

下面对这五个区域展开深入的介绍。

1.1 程序计数器

1.1.1 什么是程序计数器?

程序计数器是一块较小的内存空间,可以把它看作当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的那一条字节码指令的地址。

注:但是,如果当前线程正在执行的是一个本地方法,那么此时程序计数器为空。

1.1.2 程序计数器的作用

程序计数器有两个作用:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。

在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

1.1.3 程序计数器的特点是一块较小的存储空间

线程私有。每条线程都有一个程序计数器。

是唯一一个不会出现OutOfMemoryError的内存区域。

生命周期随着线程的创建而创建,随着线程的结束而死亡。

1.2 Java虚拟机栈(JVM Stack)

1.2.1 什么是Java虚拟机栈?

Java虚拟机栈是描述Java方法运行过程的内存模型。

Java虚拟机栈会为每一个即将运行的Java方法创建一块叫做“栈帧”的区域,这块区域用于存储该方法在运行过程中所需要的一些信息,这些信息包括:局部变量表 存放基本数据类型变量、引用类型的变量、returnAddress类型的变量。

操作数栈

动态链接

方法出口信息

当一个方法即将被运行时,Java虚拟机栈首先会在Java虚拟机栈中为该方法创建一块“栈帧”,栈帧中包含局部变量表、操作数栈、动态链接、方法出口信息等。当方法在运行过程中需要创建局部变量时,就将局部变量的值存入栈帧的局部变量表中。

当这个方法执行完毕后,这个方法所对应的栈帧将会出栈,并释放内存空间。

注意:人们常说,Java的内存空间分为“栈”和“堆”,栈中存放局部变量,堆中存放对象。

这句话不完全正确!这里的“堆”可以这么理解,但这里的“栈”只代表了Java虚拟机栈中的局部变量表部分。真正的Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

1.2.2 Java 虚拟机栈的特点

(1)局部变量表的创建是在方法被执行的时候,随着栈帧的创建而创建。而且,局部变量表的大小在编译时期就确定下来了,在创建的时候只需分配事先规定好的大小即可。此外,在方法运行的过程中局部变量表的大小是不会发生改变的。

(2)Java 虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError。a) StackOverFlowError: 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。

b) OutOfMemoryError: 若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。

(3)Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。注:StackOverFlowError和OutOfMemoryError的异同?

StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。

1.3 本地方法栈

1.3.1 什么是本地方法栈?

本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法区是本地方法运行的内存模型。

本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

方法执行完毕后相应的栈帧也会出栈并释放内存空间。

也会抛出StackOverFlowError和OutOfMemoryError异常。

1.4 堆

1.4.1 什么是堆?

堆是用来存放对象的内存空间。 几乎所有的对象都存储在堆中。

1.4.2 堆的特点

(1)线程共享

整个 Java 虚拟机只有一个堆,所有的线程都访问同一个堆。而程序计数器、Java 虚拟机栈、本地方法栈都是一个线程对应一个的。

(2)在虚拟机启动时创建。

(3)垃圾回收的主要场所。

(4)可以进一步细分为:新生代、老年代。

新生代又可被分为:Eden、From Survior、To Survior。不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。

(5)堆的大小既可以固定也可以扩展,但主流的虚拟机堆的大小是可扩展的,因此当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出 OutOfMemoryError。

1.5 方法区

1.5.1 什么是方法区?

Java 虚拟机规范中定义方法区是堆的一个逻辑部分。方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。

1.5.2 方法区的特点线程共享 方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享的。整个虚拟机中只有一个方法区。

永久代 方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。

内存回收效率低 方法区中的信息一般需要长期存在,回收一遍内存之后可能只有少量信息无效。 对方法区的内存回收的主要目标是:对常量池的回收 和 对类型的卸载。

Java虚拟机规范对方法区的要求比较宽松。 和堆一样,允许固定大小,也允许可扩展的大小,还允许不实现垃圾回收。

1.5.3 什么是运行时常量池?

方法区中存放三种数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。

我们一般在一个类中通过public static final来声明一个常量。这个类被编译后便生成Class文件,这个类的所有信息都存储在这个class文件中。

当这个类被Java虚拟机加载后,class文件中的常量就存放在方法区的运行时常量池中。而且在运行期间,可以向常量池中添加新的常量。如:String类的intern()方法就能在运行期间向常量池中添加字符串常量。

当运行时常量池中的某些常量没有被对象引用,同时也没有被变量引用,那么就需要垃圾收集器回收。

1.6 直接内存

直接内存是除Java虚拟机之外的内存,但也有可能被Java使用。

在NIO中引入了一种基于通道和缓冲的IO方式。它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需先将外面内存中的数据复制到堆中再操作,从而提升了数据操作的效率。

直接内存的大小不受Java虚拟机控制,但既然是内存,当内存不足时就会抛出OOM异常。

1.7 综上所述Java虚拟机的内存模型中一共有两个“栈”,分别是:Java虚拟机栈和本地方法栈。 两个“栈”的功能类似,都是方法运行过程的内存模型。并且两个“栈”内部构造相同,都是线程私有。 只不过Java虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈是描述Java本地方法运行过程的内存模型。

Java虚拟机的内存模型中一共有两个“堆”,一个是原本的堆,一个是方法区。方法区本质上是属于堆的一个逻辑部分。堆中存放对象,方法区中存放类信息、常量、静态变量、即时编译器编译的代码。

堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器主要的工作区域。

程序计数器、Java虚拟机栈、本地方法栈是线程私有的,即每个线程都拥有各自的程序计数器、Java虚拟机栈、本地方法栈。并且他们的生命周期和所属的线程一样。 而堆、方法区是线程共享的,在Java虚拟机中只有一个堆、一个方法栈。并在JVM启动的时候就创建,JVM停止才销毁。

第二章 揭开Java对象创建的奥秘

2.1 对象的创建过程

当虚拟机遇到一条含有new的指令时,会进行一系列对象创建的操作:

(1)检查常量池中是否有即将要创建的这个对象所属的类的符号引用;若常量池中没有这个类的符号引用,说明这个类还没有被定义!抛出ClassNotFoundException;

若常量池中有这个类的符号引用,则进行下一步工作;

(2)进而检查这个符号引用所代表的类是否已经被JVM加载;若该类还没有被加载,就找该类的class文件,并加载进方法区;

若该类已经被JVM加载,则准备为对象分配内存;

(3)根据方法区中该类的信息确定该类所需的内存大小;

一个对象所需的内存大小是在这个对象所属类被定义完就能确定的!且一个类所生产的所有对象的内存大小是一样的!JVM在一个类被加载进方法区的时候就知道该类生产的每一个对象所需要的内存大小。

(4)从堆中划分一块对应大小的内存空间给新的对象;分配堆中内存有两种方式:指针碰撞 如果JVM的垃圾收集器采用复制算法或标记-整理算法,那么堆中空闲内存是完整的区域,并且空闲内存和已使用内存之间由一个指针标记。那么当为一个对象分配内存时,只需移动指针即可。因此,这种在完整空闲区域上通过移动指针来分配内存的方式就叫做“指针碰撞”。

空闲列表 如果JVM的垃圾收集器采用标记-清除算法,那么堆中空闲区域和已使用区域交错,因此需要用一张“空闲列表”来记录堆中哪些区域是空闲区域,从而在创建对象的时候根据这张“空闲列表”找到空闲区域,并分配内存。 综上所述:JVM究竟采用哪种内存分配方法,取决于它使用了何种垃圾收集器。

(5)为对象中的成员变量赋上初始值(默认初始化);

(6)设置对象头中的信息;

(7)调用对象的构造函数进行初始化;

此时,整个对象的创建过程就完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370463.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java.lang.ClassNotFoundException:如何解决

本文适用于当前面临java.lang.ClassNotFoundException挑战的Java初学者。 它将为您提供此常见Java异常的概述,这是一个示例Java程序,可支持您的学习过程和解决策略。 如果您对与更高级的类加载器相关的问题感兴趣,我建议您复习有关java.lang…

iOS10 App跳转到系统设置

实现类似万能钥匙中点击一个Wi-Fi跳转到系统Wi-Fi设置界面的功能。 NSString * urlString "App-Prefs:rootWIFI";if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlString]]) {if ([[UIDevice currentDevice].systemVersion doubleValue…

python生成器 图片分类_python批量处理图片图片Python迭代器和生成器介绍

Python迭代器和生成器介绍迭代器迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。在for循环中,Python将自动调用工厂函数iter()获…

Java-IO流之BufferedReader 和BufferedWriter的使用和原理

BufferedReader和BufferedWriter出现的目的是为了对FileReader以及FileWriter的读写操作进行增强,而怎么增强呢,原理类似于使用StringBuilder,是把数据先放入他们的一个char数组中,然后再操作char数组。 使用缓冲区的字符流是使用…

小程序实践(三):九宫格实现及item跳转

效果图: 实现效果图红色线包含部分的九宫格效果,并附带item点击时间。 ------------------------------------------------------------------------------------------------------ 具体实现: 1、首先添加图片资源文件 在项目根目录新建一个…

用JavaFX编写图块引擎

随着JavaFX嵌入式版本的问世,我们的框架对于游戏开发变得越来越有趣,因为我们现在可以瞄准平板电脑和智能手机等小型消费类设备。 因此,我决定对JavaFX进行更多的游戏编写实验。 这次,我想使用Canvas对渲染进行更多控制&#xff0…

python命令行运行模式_[Python] 命令行模式阅读博客园的博文

1 #-*- coding:UTF-8 -*-2 importrequests3 from lxml importetree4 importsys5 importio6 importos789 sys.stdout io.TextIOWrapper(sys.stdout.buffer, encodinggb18030)101112 classCnBlogs:13 """"14 Auth:reader15 发表地址:…

HTML5--应用网页模板

因为刚开始写博客,只想着把知识点记录在这,也想给你们一些参考,在布局上有些没有思考太多;回过头来看,实在是不忍直视,对不住之前阅读的100 ,既然昨天的事无法挽回,那就从现在开始从新整改吧!也希望大家看了,能对你们有所帮助 1.先给大家看看效果图,好让大家有点兴趣 2.大家再来…

企业集成模式简介

在此博客文章中,我们将介绍一些企业集成模式。 这些是旨在解决集成挑战的已知设计模式。 阅读此书后,您将可以设计集成解决方案。 EIP(简而言之)是已知的设计模式,可为应用程序集成过程中遇到的问题/问题提供解决方案…

手把手教你Chrome浏览器安装Postman(含下载云盘链接)【转载】

转载自:http://www.ljwit.com/archives/php/278.html 说明: Postman不多介绍,是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。本文主要介绍下安装过程。 本文使用的是解压文件直接进行安装。是比较快速有效的安装方式,…

C语言博客作业--数据类型

题目1:7-4 打印菱形图案 1. 本题PTA提交列表 2. 设计思路 1.定义变量i,j,k,n;且声明i为要打印的行数,j是控制输出打印空格和星星,n是菱形为菱形的高 2.输入n 3.i1,j1 4.先打印上半部分,第一行到n/21行,输出…

信息隐藏将txt文件合并到jpg文件中_使用Kali Linux在图像内隐藏机密消息—可在任何Linux发行版使用

欢迎回到“Esn技术社区”!今天,我们将演示如何使用Steghide(一种可在Kali Linux上使用的流行隐写工具)在图像内隐藏消息。在计算机科学中,将信息隐藏在文件内(例如图像,文档,程序,有用数据,消息…

Spring 3.1,Cloud Foundry和本地开发

这篇文章将帮助您在Cloud Foundry上使用MongoDB构建Spring 3.1 Web应用程序。 除了推动Cloud Foundry之外,您还可以使用MongoDB实例在本地环境中进行开发。 目标 此博客发布的目标是在本地构建应用程序,然后发布到本地Cloud Foundry实例。 我们将利用C…

Spring MVC 简述:从MVC框架普遍关注的问题说起

任何一个完备的MVC框架都需要解决Web开发过程中的一些共性的问题,比如请求的收集与分发、数据前后台流转与转换,当前最流行的SpringMVC和Struts2也不例外。本文首先概述MVC模式的分层思想与MVC框架普遍关注的问题,并以此为契机结合SpringMVC的…

java方法调用机制_Java方法调用机制 - osc_bkdv2it5的个人空间 - OSCHINA - 中文开源技术交流社区...

最近在编程时,修改方法传入对象的对象引用,并没有将修改反映到调用方法中。奇怪为什么结果没有变化,原因是遗忘了Java对象引用和内存分配机制。本文介绍3个点:① 该问题举例说明② 简要阐述Java内存区域③ 介绍JVM中方法调用的机制…

CSS染色图标(图片)

之前一直以为用background引入的图标无法染色&#xff08;非字体图标&#xff09;&#xff0c;现在才知道有黑科技可以用&#xff0c;就是利用drop-shadow。 代码示例 <!DOCTYPE html> <html> <head lang"en"><meta charset"UTF-8"&…

eclipse安装java web插件

1 查看eclipse版本 找到eclipse的安装目录&#xff0c;找到readme文件&#xff0c;打开其中的html文件&#xff0c;我的是4.6版本的,代号是oxygen 2 安装 打开eclipse,点击help-Install new software-单击add&#xff0c;在弹出窗口中输入网址&#xff1a; http://download.ecl…

python正则表达式指南_Python正则表达式指南

1. 正则表达式基础1.1. 简单介绍正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具&#xff0c;拥有自己独特的语法以及一个独立的处理引擎&#xff0c;效率上可能不如str自带的方法&#xff0c;但功能十分强大。得益于这一点&#xff0c;在提供了正则表达…

Google Guava EventBus用于事件编程

在任何软件应用程序中都是如此&#xff0c;有些对象需要共享信息才能完成工作。 在Java应用程序中&#xff0c;实现信息共享的一种方法是拥有事件侦听器&#xff0c;其唯一目的是在发生所需事件时采取某些措施。 在大多数情况下&#xff0c;此过程有效&#xff0c;并且最有经验…

system类

package system.cn; /** system类的方法 都是静态方法&#xff0c;可以直接用类名直接调用* 常用的方法&#xff1a;* static long currentTimeMillis() 返回以毫秒为单位的当前时间。 static void exit(int status) 终止当前正在运行的 Java 虚拟机。 static void gc…