jvm----前传

前言

姑且叫jvm前传,因为上来就讲jvm内存模型有些突兀,总想写点东西引出jvm来,如下:
面试中,在问到 jvm 内存模型相关知识时,因其较理论化,为了在死记硬背时有个更概括的认识,上图,了解jvm在我们经常用到的计算机中所处的位置:
在这里插入图片描述可见,jvm的堆栈是处在操作系统(OS)的堆部分的,操作系统也是有堆栈之分的,操作系统的栈是操作系统管理分配的,随时会被回收,所以jvm内存放在操作系统堆中,这也是gc存在的意义。

知识点:jdk、jre、jvm

JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK);
在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。

知识点:jvm的组成

jvm = 2个子系统 + 2 个组件
1、Classloader子系统:1)bootStrap 是c++程序 2)bootStrap、extClassLoader、appClassLoader非继承关系,而是组合关系,具备优先级的层次,向jdk的几个jar是优先加载的,保证java程序的稳定性;
2、Executionengine(执行引擎)子系统;
3、Runtimedataarea(运行时数据区域)组件(主要包含:方法区,堆,虚拟机栈,本地方法栈,程序计数器)
4、Nativeinterface(本地库接口)组件:1)本地方法库接口:即操作系统所使用的编程语言的方法集,是归属于操作系统的。 2)本地方法库保存在动态链接库中,即.dll(windows系统)文件中,格式是各个平台专有的

知识点:类加载相关

类如何加载的,加载到什么地方,如何加载需遵循的原则,以及加载后的运行过程,如何管理竞争问题,主要管理线程类。
1、双亲委派模型:通俗的讲,某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器(到自己指定类加载路径下),依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
2、用户线程、守护线程:
重点介绍守护线程:Thread.setDaemon(True),且在线程start前设置,存在的意义是主要执行一些后台任务,程序退出时能够自动关闭。如GC就是守护线程。java的虚拟机中,只要有任何非守护线程还没有结束,java虚拟机的实例都不会退出。

知识点:内存模型

1、堆与方法区的比较:对象是类的实例(经典)。
堆:堆里存放对象和数组(存放的是实实在在的有血有肉的实例对象);
方法区:类信息、方法信息、逻辑指令等(存放的是描述对象的文字信息,如名字,身高等);
再来,方法区中的类是唯一的,而类可以new出多个实例,然后分配到堆中。
如: Student s = new Student("小明“,18);
其中s是指针,在栈中;
Student ("小明“,18)是对象,在堆中;
Student类信息存放在方法区;类加载时,会先去方法区判断是否加载过,所以方法区中的类是唯一的。且都是运行时使用,不可以被GC,是永久代。
2、方法区中的内容是加载整个工程的类信息,从性能上讲是边加载边执行,但是也可以懒加载啊,如tomcat加载spring工程时,如果想让程序启动快 一点,一些类在真正使用的时候再加载,也是可以的。
3、方法区、堆、栈
类加载器加载类信息到方法区----> 压如栈顶(先进先出)---->遇到new时就在堆中开辟类空间,栈中存放对象地址
4、本地方法区(native)
带native修饰符的方法,其实现是由非就java代码外部实现,被保存在本地方法栈,调用时调用的是本地方法栈的某个方法地址,然后直接与操作系统交互,整个过程未经过jvm引擎。

知识点:GC相关

gc回收不是创建的变量为空时被立刻回收,而是超出变量的作用域后被自动回收。

知识点:为什么会有竞争

运行时数据内存区中虚拟机栈、pc寄存器、本地方法栈是每个线程都有的,很明显这些都是独立的不会发生线程不安全的问题,但是我们平时讨论的线程不安全、要加锁等等情况是如何解释?
在这里插入图片描述在CPU内部有一组CPU寄存器,也就是CPU的储存器。CPU操作寄存器的速度要比操作计算机主存快的多。在主存和CPU寄存器之间还存在一个CPU缓存,CPU操作CPU缓存的速度快于主存但慢于CPU寄存器。某些CPU可能有多个缓存层(一级缓存和二级缓存)。计算机的主存也称作RAM,所有的CPU都能够访问主存,而且主存比上面提到的缓存和寄存器大很多。
当一个CPU需要访问主存时,会先读取一部分主存数据到CPU缓存,进而在读取CPU缓存到寄存器。当CPU需要写数据到主存时,同样会先flush寄存器到CPU缓存,然后再在某些节点把缓存数据flush到主存。
1、共享对象对各个线程的可见性2. 共享对象的竞争现象
要解决共享对象可见性这个问题,我们可以使用java volatile关键字。 Java’s volatile keyword. volatile 关键字可以保证变量会直接从主存读取,而对变量的更新也会直接写到主存。volatile原理是基于CPU内存屏障指令实现的。
synchronized代码块可以保证同一个时刻只能有一个线程进入代码竞争区,synchronized代码块也能保证代码块中所有变量都将会从主存中读,当线程退出代码块时,对所有变量的更新将会flush到主存,不管这些变量是不是volatile类型的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值