百度网站链接提交软件工程师招聘简章

当前位置: 首页 > news >正文

百度网站链接提交,软件工程师招聘简章,宣武富阳网站建设,企业信息查询官网系统1.JVM内存区域 一个运行起来的java进程就是一个Java虚拟机#xff0c;就需要从操作系统中申请一大块内存。 内存中会根据作用的不同被划分成不同的区域#xff1a; #xff08;1#xff09;栈#xff1a;存储的内容是代码在执行过程中#xff0c;方法之间的调用关系就需要从操作系统中申请一大块内存。 内存中会根据作用的不同被划分成不同的区域 1栈存储的内容是代码在执行过程中方法之间的调用关系栈中每一个元素就是一个栈帧代表一个方法的调用包含方法的形参返回值局部变量。 2堆这里存储的内容是代码中new的对象 3方法区1.8开始元数据区存储类对象.class文件加载到内存就成为了类对象 4程序计数器存放每个线程下一条指令执行的地址。空间较小主要就是用来存放一个“地址”表示下一条要执行的指令在内存的哪个地方在方法区中去找下一条指令指令是以二进制的形式存储在类对象中。 程序计数器中的值会随着指令的执行从而自动进行更新去指向下一条指令。 如果是顺序执行的代码那么下一条执行的指令地址就是把指令地址进行递增。 如果是条件循环执行的代码那么下一条执行的指令地址就可能会跳到比较远的地址。 ps栈和程序计数器每一个java线程一份而堆和方法区是每一个java进程一份。仅限java放在c中就不一定是这样了 2.JVM类加载 1基本流程 java代码经过编译后生成.class文件java程序要想运行起来就需要将jvm读取这个.class文件并且把里面的内容构造成类对象保存到内存的方法区中。 官方文档中把类加载的过程分成了5个步骤 1加载找到.class文件并且打开文件读取文件中的内容通过全限定名称查找 2验证检查当前二进制文件是否符合格式的要求具体格式 3准备给类对象分配内存空间并且为不被final修饰的static变量赋初始默认值被final修饰的变量在此时会被赋值成程序员给定的值 4解析针对类对象中字符串常量的处理进行了一些初始化的操作。符号引用到直接引用 字符串常量在经过编译之后egfinal String s hellos本来是存储内存地址但在.class文件中会重新针对该字符串进行创建出一个引用此时这个引用就不是存储内存地址了而是存储文件偏移量字符串长度通过这个变量就可以知道目前字符串处于哪个位置。到解析的阶段类加载的时候会重新将这个引用替换成内存地址。 5初始化对类对象中的各种属性进行初始化还需执行静态代码块和加载一下父类子类中调用构造方法会先帮助父类进行构造 2双亲委派模型 是在加载过程中的第一个步骤。 首先需要了解一下类加载器 是JVM中的一个模块JVM内置了三个类加载器 1BootStrap ClassLoader 2Extension ClassLoader 3Application ClassLoader 这三个类加载器之间的关系就好似爷父子之间的关系但不是靠继承构成的而是由类加载中的一个属性parent来指向父类加载器。 加载的具体流程是 ①根据给定的全限定类名找到对应的.class文件。 ②从Application ClassLoader作为入口开始执行查找的逻辑。 ③Application ClassLoader不会立即扫描自己所负责的目录负责搜索项目当前目录和第三方库的对应目录而是会交给自己的父类加载器Extension ClassLoader。 ④Extension ClassLoader不会立即扫描自己所负责的目录负责搜索JDK中一些扩展库对应的目录是JDK标准库之外的一些库属于对JDK标准库的扩展而是会交给自己的父类加载器BootStrap ClassLoader。 ⑤BootStrap ClassLoader也不会立即扫描自己所负责的目录负责搜索JDK标准库对应目录而是会交给自己的父类加载器但是却发现没有父类加载器因此只能区扫描自己负责的目录一旦在标准库中查找到对应类的.class文件此时加载的过程就完了扫描结束过后如果没有扫描到就会交给它的子类加载器Extension ClassLoader扫描。 ⑥如果在Extension ClassLoader扫描到了就结束加载过程没有扫描到就交给它的子类加载器Application ClassLoader扫描。 ⑦如果在Application ClassLoader扫描到了就结束加载过程没有扫描到此时应该交给它的子类加载器扫描但是发现没有了所以此时会抛出一个异常ClassNotFoundException 总结所谓的双亲委派模型其实就是一个按照优先级查找.class文件的一个过程之所以有这么一套流程是为了确保JDK标准库扫描的优先级最高其次是扩展库最后才是项目当前目录和引入的第三方库对应目录。就好比你在自己的代码中使用String导入的包是java.lang.String在类加载的时候加载的JDK标准库中的类而不是自己写的这个类。 3.JVM垃圾回收机制GC垃圾回收 在java中new对象是动态申请内存运行时分配如果一个资源申请了内存空间长时间不使用但是不释放就可能会造成内存泄漏。 在java中给出了一个方案也就是垃圾回收机制让JVM自动判定某个内存是否不再使用了 如果后面这个内存确实不用了JVM就会自动回收把这个内存给回收掉了此时就不需要手动回收了。 GC是垃圾回收GC回收的目标是内存中的对象。对于java来说就是释放堆上的new出的对象栈上的对象是随着栈帧的生命周期方法执行结束栈帧自然销毁内存自然释放静态变量生命周期是整个程序这个始终存在就意味着静态变量无需释放的真正释放的就是堆上的对象。 GC回收垃圾的过程主要有两个步骤 1找到垃圾 有两种主流的方案 ①引用计数 new出来的对象会单独划分空间来保存有一个计数器计的是当前有多少引用指向该对象。 如果一个对象没有引用指向了即引用计数为0就可以将该对象视为垃圾了。 但是使用该种方式可能会存在两种问题 ·比较浪费内存 计数器怎么说也得有两个字节如果对象本身比较小那么此时这个计数器所占空间比例就比较大了。 ·存在循环引用问题 ②可达性分析 有一组线程周期性扫描代码中的所有对象把所有可以访问到的对象都给标记成“可达”反之如果经过扫描后不可达的对象就成垃圾了需要被回收。 eg 当然这里的遍历不一定是二叉搜索树这里可达的实现大概率是靠N叉搜索树实现这一步就是针对当前对象看对象中有多少不同引用类型的成员然后再对每一个类型的成员进行进一步的遍历。 通过上述过程不难看出可达性分析是比较耗费资源的开销较大。  2回收垃圾 有三种基本的回收思路 ①标记删除 扫描到一个不可达的对象就直接进行释放这个方案非常不好那就是会产生很多的内存碎片。释放代码是为了让其他代码能够申请一块连续的内存空间随着时间的推移内存碎片的情况就会愈演愈烈就会导致后续申请连续内存空间变得困难。 ②复制算法 通过复制的方式把有效的对象归类到一起在同一释放剩下的对象。 也就是把内存一分为二一次只用其中一半。但这种方式有两个明显的问题 a.内存利用率不高 b.如果有效的对象很多那么复制的开销将会很大 ③标记整理 既能解决内存碎片的问题又能够解决上述内存利用率不高的问题。 eg 类似于顺序表删除元素的搬运操作使用该种方式搬运开销仍然很大。 而JVM中GC垃圾回收主要思想是分代回收具体实现可能有一些调整和优化是对上述思路的集合让不同的方案扬长避短。 分代回收有一个很重要机制就是对象能活过的GC扫描轮次越多就是越老代表当前对象是暂时不会被释放的 eg下图是整个分代回收的全部过程