JVM内存结构

可以看出JVM从宏观上可以分为 ‘内部’ 及 ‘外部’  两个部分(便于记忆理解):

‘内部’包含:线程共享(公有)数据区 和 线程隔离(私有)数据区

‘外部’包含:类加载子系统、垃圾回收器、执行引擎、本地库接口、本地方法库

以上部件构成了整个jvm,接下来我们一个一个零件拆开了看。

class文件

一个java文件会通过编译工具(javac)编译成class字节码文件,通过jvm进行加载运行。因为jvm屏蔽了底层操作系统的差异(平台无关性),所以一次编译到处运行。

类加载子系统

类加载子系统:负责查找和装载class文件,将其中的二进制数据加载到jvm中。

字节码 --> 加载 -->  验证 --> 准备 --> 解析  --> 初始化

加载:通过类的完全限定名找到类文件所在位置,根据其中的字节码创建java.lang.Class对象,所以才会说万物皆对象,我们也可以继承ClassLoader,重写findClass方法来自定义实现类加载器。默认情况下我们都使用AppClassLoader

验证:确保加载的字节码的是否符合虚拟机的要求,是java提供的一种自我保护机制,不让其危害虚拟机安全。其主要包括四种验证,字节码验证、文件格式验证,元数据验证、符号引用验证。

准备:为类变量分配地址和初始化值,类变量会分配到方法区(元空间)中,这里的初始化是指该数据类型的默认初始值,例如int对应的是0,long对应的0L,只有在初始化时才会动显示赋值

解析:把类中的二进制数据中的符号引用转换为直接引用;例如我们通过user.getInfo();这里的.getInfo()就是符号引用,在解析阶段会将它指向真正的内存位置,这就是直接引用

初始化:主要为类的静态变量赋予正确的值,比如int num = 10;这里num的值会从准备阶段的0变为10;并且若该类有父类,会对其进行初始化操作;如果类中有初始化语句,系统会按照顺序进行初始化

双亲委派模式

双亲委派:自底向上检查是否加载成功,自顶向下尝试加载。

当一个类加载器收到类加载请求,它不会自己进行加载,而是将该请求丢给父类加载,如果父类还存在父类,则会依次向上请求,直到到达顶级加载器,如果父类加载器能加载完成就返回加载成功,否则子类加载器才会自己尝试加载。

System.out.println(Test.class.getClassLoader());

System.out.println(Test.class.getClassLoader().getParent());

System.out.println(Test.class.getClassLoader().getParent().getParent());

System.out.println(String.class.getClassLoader());

通过代码验证,可以很轻松的了解 AppClassLoader -> ExtClassLoader -> BootstrapClassLoader 这三层的关系。

类加载的三种方式

1. new关键字加载

User user = new User();

静态加载,在运行时候通过new关键字创建类实例

2. Class.forName()加载

Class clazz = Class.forName(“User”);

Object user=clazz.newInstance();

动态加载,通过Class.forName()来加载类,然后调用类的newInstance()方法实例化对象

3. ClassLoader 实例的 loadClass() 方法

Class clazz = classLoader.loadClass(“User”);

Object user=clazz.newInstance();

动态加载,可通过继承ClassLoader实现自定义类加载器

线程私有和线程公有

JVM内存区从宏观上可以分为 线程私有 和 线程公有 两块。

线程私有部分

这部分没有线程安全问题,随着线程执行结束而结束;包含程序计数器、虚拟机栈、本地方法栈三个部件。

程序计数器:

程序计数器也叫PC寄存器,作用是cpu进行切换的时候,指向当前时刻需要获取指令的位置。

特点:

线程私有

一块较小的区域

记录程序执行的位置

不存在内存溢出OutOfMemoryError

虚拟机栈:

栈数据结构实现,入口和出口只有一个,称之为入栈和出栈,先进后出(FILO)

栈的作用主要是执行方法,先执行的方法在最下面,然后依次放入,方法执行完毕之后从上往下依次退出;所以方法执行就是压栈,方法结束就是出栈(销毁栈帧)。

public void start(){

say();

run();

}

虚拟机栈如何执行

栈帧

栈帧存在Java虚拟机栈中,是虚拟机栈中的单位元素。方法执行会创建栈帧,一个方法就是一个栈帧,一个栈帧分为四个部分:

1. 局部变量表

存放方法参数或者内部定义的一组变量列表;例如方法中声明的对象:

User user = new User(); //局部变量user

2. 操作数栈

执行字节码指令的时候使用,通俗的讲就是方法的执行在操作数栈中进行,通过压栈和出栈进行访问

3. 动态链接

Java运行期间是动态链接的,需要将指向方法的符号引用转换为直接引用(内存地址);在类加载解析阶段,将符号引用转换为直接引用称之为静态解析。而此处正好就是动态链接

user.getInfo();  //找到这个getInfo()方法的内存位置

4. 返回地址

方法不管正常执行结束还是异常退出,需要返回方法被调用的位置

以上四个部分对应方法执行的过程。虚拟里面包含很多个栈帧,每个方法对应一个栈帧。

将一个class文件,通过bin/javap.exe文件进行反汇编可以查看出以上四个部分。

栈溢出:当栈的深度大于虚拟机允许会报StackOverflowError,-Xss可设置大小

/** 递归演示如何栈溢出 */

public static int num = 0;

public static void a(){

num++;

a();

}

public static void main(String[] args) {

try{

a();

}catch (Exception ex){

System.out.println("调用次数:"+num);

}

}

内存溢出:当栈需要扩展而无法申请空间会报OutOfMemoryError

本地方法栈

本地方法栈和虚拟机栈类似,区别在于虚拟机栈主要为jvm执行字节码服务,而本地方法栈为Native方法服务,即本地方法服务;所以本地方法栈也是一块内存私有区域,与虚拟机栈相同也有同样的异常问题。

特点:

与虚拟机栈基本类似

区域在于本地方法栈为Native方法服务(windows下调用dll文件)

Sun HotSpot将虚拟机栈和本地方法栈合并

有StackOverflowError和OutOfMemoryError

线程公有部分

这部分存在线程安全问题,平常我们所指的内存优化,溢出等问题都是需要关注这个区域。包含堆、方法区(也叫元空间)两个部件。

方法区(元空间)

类加载器加载类的时候,会将一些类的元数据信息(字节码)保存在这个区域,例如:类变量,静态方法,普通方法等,方法区是线程共享的,多个线程能用到同一个类

jdk1.7合并方法区到了堆里面

jdk1.8保留了方法区的概念,只不过实现方式不同,jdk1.8称为元空间,与堆不相连,但是与堆共享物理内存,逻辑上可以认为是在堆中

特点:

线程共享

存储类信息、常量、静态变量、方法描述等信息

HotSpot虚拟机中称之为永久代

GC很少回收这个区域

存在OutOfMemoryError,可以通过-XX:MaxPermSize设置大小

堆中用于存放所有实例化对象和数组,堆中信息线程共享,所有jvm部件中分配内存中最大的区域,在虚拟机启动时就创建,垃圾回收器主要管理该区域,堆分为新生代(占堆内存1/3)和老年代(占堆内存2/3),新生代更细致可以分为Eden、From Survivor、To Survivor空间,比例8:1:1 ;可以通过-Xmx、-Xms设置大小

在堆中产生了一个实例对象或数组,可以在栈中声明一个变量,用于指向堆中的对象,该变量的取值等于堆中对象的内存地址,所以我们在打印变量名的时候是一串内存地址

Test test = new Test();

System.out.println(test); //输出Test@1b6d3586

万物皆对象,当我们在实际开发中,创建了许多对象,为了防止内存泄露,java确保有效的使用内存,会由java虚拟机自动垃圾回收器来管理;且把堆分为新生代和老年代进行管理

新生代与老年代

新生代是Java对象出生的地方,是新对象分配内存的地方,大部分对象存活时间都不需要太久,这个区域会频繁触发MinorGC进行垃圾回收;

而老年代存放的都是存活时间较久或者内存较大的对象,所以Full GC不会频繁执行。

Minor GC

发生在新生代中的垃圾回收机制,采用复制算法(扫描存活对象,复制到一块新内存空间中),From Survivor 和 to Survivor是相对的,也就是说Minor GC发生时,Eden区和其中一个Survivor区会把一些仍然存活的对象放置另外一个Survivor 区,然后清理Eden区和之前的Survivor 区,下次同理,当达到一定 ‘年龄’ 后,新生代会把对象放入老年代(每发生一次Minor GC增加1岁,默认15岁)

Full GC

发生在老年代中的垃圾回收机制,采用标记-清除(标记存活的对象,清除未标记的对象,即需要回收的对象),因为老年代中的对象较稳定,所以发生Full GC的频率相对Minor GC较少,但是一次回收的时间会比Minor GC更长

一个上帝视角的java游戏_从上帝视角看Java如何运行相关推荐

  1. 当年的三国java游戏_三国卡牌类手游塞班 分享问几年前玩的一个三国

    分享问几年前玩的一个三国卡牌手机游戏,好像是塞班...分享问几年前玩的一个三国卡牌手机游戏,好像是塞班,或者安卓的,单机的...是塞班的,之前也玩过.里面有霹雳车,攻城云梯,什么的.骑兵,枪兵,盾兵, ...

  2. 猜物品游戏java编程_小猿圈Java初学者练习小案例:猜数字游戏

    对于Java初学者,如果没有好的引导,可能会觉得自己学什么都不好,学什么都不会,这个时候就要给他们一下小的案例,让他们去实践一下,让他们知道自己学的东西是可以用到的,小猿圈java讲师为你准备了Jav ...

  3. 有控制雷电武器的java游戏_雷电飞机射击游戏 JAVA

    一.程序概述 1.开发环境 开发程序的工具Eclipse是著名的跨平台的自由集成开发环境.一个开放源代码的.基于Java的课扩展开发平台.就其本身而言,它只是一个框架和一组服务,用与通过插件组件构建开 ...

  4. 智能手机怎么玩java游戏_智能手机可以在普通手机上玩Java游戏吗?

    当然可以是2113. 某些智能手机需要首先在5261上安装JAVA平台,但是选择平台程序4102,否则会出现不稳定的情况. 尽管JAVA游戏非常受欢迎,但它们在1653年也很新,但总比没有好. 玩经典 ...

  5. java语言开发手机游戏_手机上的JAVA游戏和JAVA软件,是电脑上的JAVA语言编写的吗?他们之间有什么联系...

    手机上的JAVA游戏和JAVA软件,是电脑上的JAVA语言编写的吗?他们之间有什么联系以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起 ...

  6. 龙之谷穿越java游戏_龙之谷2java手机游戏下载

    龙之谷2java游戏客户端专为java游戏玩家打造的手机版本,这是一款画面高清细腻的策略战斗手游,这款手游采用精致画面为你描绘出一个美丽的魔幻世界等着你来冒险,还有打击感满满的打斗现场等着你的到来,喜 ...

  7. 那些年的java游戏_那些年我们曾为之痴迷的经典JAVA游戏(3)

    彩虹六号 <彩虹六号>和一般意义上的第一人称射击游戏有所不同,更侧重于战术层次上的策略.或许这款游戏的画面现在看起来很渣,但那时在JAVA平台上已经属于画面非常好的游戏了,同样属于早期手游 ...

  8. 画质超高的仙侠java游戏_画质超高的游戏有哪些?顶级画质大型游戏盘点

    每个人都有每个人所喜欢的东西,一款游戏也一样,有的人喜欢打击感,有的人喜欢好剧情,有的人喜欢高画质等等等,游戏画面,特效,和战斗过程对显卡是考验,还有环境,画质,分辨率,有些有些可以调细节,细节越高越 ...

  9. 自由度比较高的java游戏_自由度超高的五款游戏,虽然是单机,但是玩家依旧很多!...

    原标题:自由度超高的五款游戏,虽然是单机,但是玩家依旧很多! <合金配备5:幻痛>,玩法比比拟特殊,作为一名玩家的你将成为游戏中的一个角色.在游戏中你首先需求做的就是"埋伏&qu ...

最新文章

  1. 人月神话阅读笔记02
  2. git 忽略文件失效
  3. objc_setAssociatedObject 关联的简单用法
  4. KEIL常见编译错误和警告解决方案汇总
  5. 洛谷-P3203 弹飞绵羊 分块
  6. mysql order by int_mysql order by是怎么工作的?
  7. oracle 匿名段,这段匿名块看着没什么问题啊
  8. Linux ping ipv66,IPV6的测试-ipv6网卡配置-ipv6的nginx配置-ipv6的ping测试-ipv6的curl测试...
  9. 计算机office基础知识的试题,office计算机基础知识(附答案).doc
  10. 需求分析的初稿出来了
  11. linux下RTNETLINK answers: File exists的解决方案
  12. weblogic环境,应用上传图片报Could not initialize class sun.awt.X11.XToolkit
  13. 9套Android实战经典项目
  14. dnf外挂java代码,使用Java实现简朴的斗地主案例_rust辅助,绝地求生卡盟
  15. 【渝粤教育】电大中专计算机常用工具软件_1作业 题库
  16. 自动补全 (自定义)拼音分词器 搜索时注意事项
  17. 超详细的Latex快速基础入门 (第二节)【关于latex命令的一些知识】
  18. cgb2107-day08
  19. HTML+css+javascript面试题
  20. 苹果手机还原网络设置会怎样_苹果手机信号不好,那是因为你没这样设置,这样设置信号顶呱呱...

热门文章

  1. 2019年全网首发-vSphere 7之VCSA 7.0 RC部署指南(转载)
  2. Java基础学习总结(172)——手写Java 重试机制
  3. 消息中间件学习总结(20)——主流MQ比较及MQ常见使用场景总结
  4. Netty学习总结(6)——Netty使用注意事项
  5. java自学难点_分享在达内教育培训Java的感受
  6. django 坑~~
  7. Sublime Text 3 快捷键及使用技巧
  8. 基本排序(C语言版)
  9. 批量修改一张表格的多个sheet名
  10. 如何查找android emulator内核的精确版本