【刨根问底】之JVMpart1(抽象数据类型,jvm内存空间结构,栈,寄存器,直接内存,线程概念,多线程概念,native方法)

1.面向对象的编程

补完上述概念后,当我们要实行"面向对象的编程"行为的话,我们需要做一些什么呢:
1,抽象数据类型
2,继承
3,多态
4,封装
pass:抽象数据类型指的是,将具体问题中的元素,按照
1.数据
2.关联&行为(也就是特征)
三个要素进行抽象化的行为
然而上,除了这些基础技能点,我们还有一些额外的需要考虑的问题,其中最为重要的就是——对象的创建和存在时间

2.对象的创建和存在时间
我们都知道,我们设计,定义类,在通过类实例化对象,这些对象彼此发送信息达成所需要的结果
而此处我们要讨论的问题就是:
1.对象创建后存放在哪?
2.对象何时被创建又何时被释放?
每一种语言对于这两个问题都有自己的选择,在讨论这个问题前我认为有必要先讨论java的内存空间java程序的运行过程
这是书本的额外内容,可能在书本的后续会提及,但是在讨论对象放在何处前,我们应该知道java能有哪些地方用来存放
在讨论对象在什么时候被销毁前,也应该先讨论java程序的运行经过了哪些阶段

1.1java的内存空间

1.1.1jvm内存空间是什么
一段java程序在执行时,会先由javac编译器转化为class字节码文件,再交给java虚拟机(JVM),接着jvm中的类加载器将其编译后,交给JVM内存,再由执行引擎执行代码
在这里插入图片描述
此处的JVM内存就是我们需要重点关注的内存空间,而后,我们就要讨论其内部的具体结构
在这里插入图片描述
为了理解这张图,首先
1.1.2什么是线程
一个程序,代表了一个进程,而一个进程包含了多个线程,
进程是资源分配的单位,比如对于操作系统来说,运行了一个程序,此时我们称,分配了一个进程给他
线程是具体的调度和操作,程序执行后,至少会先执行一个入口函数,然后可能会有打开窗体的函数执行等等,这些调度和操作,都是线程
一个进程至少拥有一个线程,在java中就体现为一个程序至少有一个main方法作为线程入口

然后
1.1.3什么是线程私有
此块区域在分配给一个线程后,其相对于其他线程来说是一个独立独享的区域,这被称为线程私有——
比如,众所周知,方法中定义的局部变量是各个方法之间独立的,这是因为局部变量的存放于线程私有区
而一个定义出来的对象是多个方法间都公用的,这是因为对象被定义在线程公用区

理解了大致的分类后,我们再开始对每一块区域的功能进行分析:
1.2jvm虚拟栈
1.栈的本质是一种遵守先进后出的数据存储结构,插入和释放的本质是指针的上下移动,因此其读取速度非常快
2.栈调度指针的函数在存入数据时,有两个参数是必须已知的:每个存入的数据的具体存在时间,以及其具体大小,在java中,因为这个特点,栈一般不用来存放对象
3.因为其速度快且先进后出的运行模式,通常作为方法执行的内存模型
4.先进后出的运行模式为什么是优势?
方法调用时,main方法运行启动线程,开辟一个独立的栈帧,此时,main方法中若调用了其他方法,该方法将会开辟下一个新栈帧,由于先进后出,所以main会最后被释放,这正好符合方法的运行逻辑
5.在java中,栈帧中存放的元素有很多但是我们最应该关注的是:局部变量,也就是方法的参数,以及方法内部的变量

1.3.本地方法栈
1.其本质和虚拟栈形式相同,但是其执行的是特殊的本地类型的方法
2.什么是本地方法
他们是一系列被native修饰了的方法,其形式和abstract类似,没有具体的实现代码,但是这种方法并不是希望其他人继承,而是其具体实现存在于dll库文件中,这种方法在java底层中被广泛的运用
3.在很多虚拟机中,本地方法栈和虚拟机栈实则合并在同一个空间中

1.4.程序计数器
1.其又名寄存器,是所有内存中读写速度最快的区域,而且,他的存在是为了本就是为了提升效率与速度的多线程服务,那么

1.4.1什么是多线程?

1.4.1.1多线程的需求缘由
我们以一个常见的事情为例,一个祖安人打开聊天框喷人,点击发送,调用信息发送方法,若只有一个线程,那么根据栈的先进先出
在这里插入图片描述
可以看到,方法一以调用的方式唤醒了方法二,由于栈的先进后出,导致方法一被挂起需要等待方法二执行完毕才可以继续后续的逻辑,这对于在搓王者的玩家来说这肯定是无法接受的,自然应该在输入后就能马上返回游戏,因此就有了多线程的概念
1.4.1.2多线程带来的变化
在这里插入图片描述
此时,被唤醒的消息发送方法有了自己独立的栈帧,和方法一没有了先后关系,因此方法一不需要等待其发送完毕再继续

1.4.1.3多线程的底层内存实现
正如作为人类只有一个脑子,并不能同时玩手机和听课,若要达成这种效果,只能听课和玩手机再以较短持续时间交错进行,cpu在处理多线程也是如此,其本质是多个线程交错执行,而为了记住上一个线程指到何处,需要一个单独的存放区域,因此有了程序计数器这一内存区域

2.其不会产生内存溢出错误,因为其记录的内容本质只是字节码文件的行号,也就只是一个书签而已,jvm在初始化时就会为他配置一个绝对不会溢出的大小

3.当执行的程序为native程序时,不会写入行号——因为之前已经说明native方法是独立于jvm运行的库函数,其运行的位置并不位于jvm中,因此其标签自然不会写在jvm中的寄存器中

1.5直接内存
1.非常明显,直接内存的位置并不处于jvm之中,又有另外一个名字,叫做堆外内存
2.其大小不受jvm限制——因为她不处于jvm之中,但是毕竟仍然是内存,会受到外部存储内存的原因,由于堆内存是可以手动设置大小的,可能存在将堆内存设置的过大导致直接内存空间不足而导致oom错误
3.直接内存在jdk1.4被引入,本质上指的是,java代码通过DirectBuffer可以申请的一块jvm以外的区域,底层有native函数创建,并在堆中创建DirectByteBuffer对象来存放地址的引用以操作这块内存
直接内存使用实操
4.直接内存的GC
对于一个有固定大小,会达到爆满的空间肯定是存在其对应的GC的,对外内存存放于堆外,同时会将自己的引用,也就是DirectByteBuffer对象存放于jvm之中,DirectByteBuffer对象在创造时,会创建一个对应的clean对象
当DirectByteBuffer被判定为死亡,clean对象将会在下次FullGC时调用堆外内存的删除方法,将其清除,当堆外内存被删除后,clean对象也会在下次gc时死亡

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值