设计师网站软件做网站模板和服务器是一样的吗
2026/2/20 23:54:52 网站建设 项目流程
设计师网站软件,做网站模板和服务器是一样的吗,优化百度seo技术搜索引擎,丰台周边网站建设一、虚拟机的结构 Java 虚拟机#xff08;JVM#xff09;是一个抽象的计算机器#xff0c;它通过在实际的计算机上模拟各种计算机功能来运行 Java 程序。它的核心作用是将 Java 字节码#xff08;.class文件#xff09;翻译成特定操作系统和硬件平台的机器指令#xff0c…一、虚拟机的结构Java 虚拟机JVM是一个抽象的计算机器它通过在实际的计算机上模拟各种计算机功能来运行 Java 程序。它的核心作用是将 Java 字节码.class文件翻译成特定操作系统和硬件平台的机器指令从而实现 Java 的核心特性“一次编写到处运行”Write Once, Run Anywhere。JVM的结构主要由下面的三个子系统和两个内存区域组成三大子系统类加载子系统运行时数据区方法区、堆、虚拟机栈、程序计数器、本地方法栈执行引擎两大内存区域本地方法接口JNI本地方法库1.1 类加载器子系统类加载子系统负责从文件系统或者网络中加载Class 信息加载的类信息存放于一块称为方法区的内存空间。除了类的信息外方法区中可能还会存放运行时常量池信息包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)。它负责加载、链接和初始化 .class文件字节码文件。加载 (Loading)通过类的全限定名如 java.lang.String找到并读取 .class文件的二进制数据然后在方法区中创建一个代表这个类的 java.lang.Class对象。链接 (Linking)分为三个步骤验证 (Verification)确保被加载的 .class文件符合 JVM 规范是安全且正确的防止恶意代码破坏。这是 Java 安全模型的重要一环。准备 (Preparation)为类的静态变量分配内存并设置默认初始值零值例如 static int a会被初始化为 0。解析 (Resolution)将常量池中的符号引用例如类名、方法名转换为直接引用具体的内存地址。初始化 (Initialization)执行类的静态代码块 (static {}) 和为静态变量赋予程序员定义的初始值例如 static int a 100;。1.1.1 主要职责publicclassClassLoaderSystem{/* * 类加载器子系统职责 * 1. 加载读取.class文件到内存 * 2. 链接验证、准备、解析 * 3. 初始化执行类构造器clinit() * * 类加载过程加载 → 链接(验证→准备→解析) → 初始化 */// 双亲委派模型publicclassParentDelegationModel{/* * 类加载器层级 * 1. Bootstrap ClassLoader启动类加载器 * - 加载核心类库rt.jar、charsets.jar等 * - C实现Java中显示为null * * 2. Extension ClassLoader扩展类加载器 * - 加载扩展目录jre/lib/ext/*.jar * - Java实现sun.misc.Launcher$ExtClassLoader * * 3. Application ClassLoader应用类加载器 * - 加载classpath下的类 * - Java实现sun.misc.Launcher$AppClassLoader * * 4. 自定义ClassLoader * - 用户自定义的类加载器 */}}1.1.2 类加载过程代码示例publicclassClassLoadingProcess{static{System.out.println(静态代码块执行 - 初始化阶段);}publicstaticfinalintCONST_VALUE100;// 准备阶段分配内存并设零值// 初始化阶段赋值为100publicstaticvoidmain(String[]args)throwsException{// 演示类加载过程ClassLoaderloaderClassLoader.getSystemClassLoader();Class?clazzloader.loadClass(com.example.MyClass);// 触发初始化Class.forName(com.example.MyClass);}}双亲委派模型 (Parent Delegation Model)这是类加载器的工作机制。当一个类加载器收到加载请求时它不会自己先尝试加载而是将这个请求委派给父类加载器去完成。只有当父类加载器无法完成加载时子加载器才会尝试自己加载。这保证了 Java 核心库如 java.lang包的安全性防止被用户自定义的类替代。1.2 运行时数据区这是 JVM 内存管理的核心区域用于存储程序运行时的数据。1.2.1 方法区JDK1.7被称之为永久区 JDK1.8之后消失变成元空间Meta space)来进行存储我们的类代替方法区的Meta space是分配到直接内存当中的。存储内容已被加载的类信息类名、父类、方法、变量等元数据、常量、静态变量、即时编译器编译后的代码缓存。注意在 HotSpot JVM 中方法区常被称为 “永久代” (PermGen)Java 8 之前但自 Java 8 起永久代被移除取而代之的是 元空间 (Metaspace)。元空间使用本地内存而非 JVM 内存大大减少了内存溢出的可能性。方法区MethodArea逻辑结构 ┌──────────────────────────────────────┐ │ 方法区MethodArea │ ├──────────────────────────────────────┤ │1.类型信息ClassMetadata │ │ ├── 类基本信息 │ │ ├── 常量池 │ │ ├── 字段信息 │ │ ├── 方法信息 │ │ └── 类加载器引用 │ ├──────────────────────────────────────┤ │2.运行时常量池RuntimeConstantPool│ │ ├── 字面量Literals │ │ ├── 符号引用SymbolicReferences│ │ └── 直接引用DirectReferences │ ├──────────────────────────────────────┤ │3.静态变量StaticVariables │ │ ├── 基本类型静态变量 │ │ ├── 引用类型静态变量 │ │ └── 静态常量finalstatic │ ├──────────────────────────────────────┤ │4.即时编译器代码缓存CodeCache │ │ ├── 已编译的本地代码 │ │ ├── 方法字节码 │ │ └── 方法元数据 │ ├──────────────────────────────────────┤ │5.方法字节码MethodBytecode │ │6.JIT 编译信息JITMetadata │ │7.类变量初始值ClassVariableInit│ └──────────────────────────────────────┘1.2.2 堆Java堆是和Java应用程序关系最为密切的内存空间几乎所有的对象都存放在堆中。并且Java堆是完全自动化管理的通过垃圾回收机制垃圾对象会被自动清理而不需要显式地释根据垃圾回收机制的不同Java堆有可能拥有不同的结构。最为常见的一种构成是将整个Java堆分为新生代和老年代。新生代包含EdenSurvivor区survivor区里面分为from和to区内存回收时如果用的是复制算法从from复制到to我们也教s0s1当经过一次或者多次GC之后存活下来的对象会被移动到老年区其中新生代有可能分为eden区、s0区、s1区s0 和s1也被称为from和to区域它们是两块大小相等、可以互换角色的内存空间。在绝大多数情况下对象首先分配在eden区在一次新生代回收后如果对象还存活则会进入s0或者s1之后每经过一次新生代回收 对象如果存活它的年龄就会加1。当对象的年龄达到一定条件后就会被认为是老年对象从而进入老年代。**存储内容**几乎所有对象实例和数组都在这里分配内存。这是 JVM 中最大的一块内存区域是垃圾回收器 (Garbage Collector, GC) 管理的主要区域因此也被称为“GC 堆”。结构为了更好的进行内存管理和垃圾回收堆空间又细分为新生代 (Young Generation)新创建的对象首先在这里分配。它又分为一个 Eden 区和两个 Survivor 区 (S0, S1)。老年代 (Old Generation)在新生代中经历多次 GC 后仍然存活的对象会被晋升到这里。注意Java 8 之后还有一个元空间 (Metaspace)但它不属于堆而是使用本地内存。展示Java堆、方法区和Java栈之间的关系:publicclassSimpleHeap{privateintid;publicSimpleHeap(intid){this.idid;}publicvoidshow(){System.out.println(My ID is id);}publicstaticvoidmain(String[]args){SimpleHeaps1newSimpleHeap(1);SimpleHeaps2newSimpleHeap(2);s1.show();s2.show();}}上述代码声明了一个SimpleHeap类并在main(函数中创建了两个SimpleHeap实例。此时各对象和局部变量的存放如图所示。SimpleHeap实例本身分配在堆中描述SimpleHeap类的信息存储在方法区main中的s1和s2的局部变量存储在栈中并且指向两个实例。1.2.3 虚拟机栈Java栈是一块线程私有的内存空间。如果说Java堆和程序数据密切相关那么Java栈就是和线程执行密切相关的。线程执行的基本行为是函数调用,每次函数调用的数据都是通过Java栈传递的。Java栈只支持出栈和入栈两种操作。线程私有生命周期与线程相同。每个方法在执行时都会创建一个栈帧 (Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法从调用到执行完成就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。我们常说的“栈内存”指的就是这里存储局部变量等。1.2.3.1 栈帧在Java栈中保存的主要内容为栈帧。每一次函数调用 都会有一个对应的栈帧被压入Java栈每一个函数调用结束都会有一个栈帧被弹出Java栈。栈帧就是对象不是变量等。后入先出栈帧包含局部变量表、操作数栈、栈数据区栈帧的结构图解释函数1对应栈帧1,函数2对应栈帧2依此类推。函数1中调用函数2函数2中调用函数3,函数3中调用函数4。当函数I被调用时栈帧1入栈;当函数2被调用时栈帧2入栈;当函数3被调用时栈帧3入栈;当函数4被调用时栈帧4入栈。当前正在执行的函数所对应的帧就是当前的帧(位于栈顶)它保存着当前函数的局部变量、中间运算结果等数据。当函数返回时栈帧从Java栈中被弹出。Java 方法有两种返回函数的方式一种是正常的函数返回使用return指令;另外一种是抛出异常。不管使用哪种方式都会导致栈帧被弹出。在一个栈帧中至少要包含局部变量表、操作数栈和帧数据区几个部分。1.2.3.2 局部变量表局部变量表用于保存函数的参数以及局部变量。局部变量表中的变量只在当前函数调用中有效当函数调用结束后随着函数栈帧的销毁局部变量表也会随之销毁。由于局部变量表在栈帧之中因此如果函数的参数和局部变量较多会使得局部变量表膨胀从而每一次函数调用就会占用更多的栈空间最终导致函数的嵌套调用次数减少。下面的代码演示了这种情况第1个recursion函数含有3个参数和10个局部变量因此其局部变量表含有13个变量。而第2个recursion()函数不含有任何参数和局部变量。当这两个函数被嵌套调用时第2个recursion函数可以拥有更深的调用层次。publicclassTestStackDeep{privatestaticintcount0;publicstaticvoidrecursion(longa,longb,longc){longe1,f2,g3,h4,i5,k6,q7,x8,y9,z10;count;recursion(a,b,c);}publicstaticvoidrecursion(){count;recursion();}publicstaticvoidmain(Stringargs[]){try{recursion(1,2,3);}catch(Throwablee){System.out.println(deep of calling count);e.printStackTrace();}}}-Xss128k调用无参数的方法-Xss128k调用有参数的方法可以看到在相同的栈容量下局部变量少的函数可以支持更深的函数调用。使用jclasslib工具可以更进一步查看函数的局部变量信息。图2.6显示了第一个recursion()函数的最大局部变量表的大小为26个字。因为该函数包含总共13 个参数和局部变量且都为long型long 和double在局部变量表中需要占用2个字其他如int、short、 byte、 对象引用等占用1个字。第一个方法第二个方法可以看到在Class文件的局部变量表中显示了每个局部变量的作用域范围、所在槽位的索引(index 列)、变量名(name 列)和数据类型(J 表示long型)。栈帧中的局部变量表中的槽位是可以重用的如果一个局部变量过了其作用域那么在其作用域之后申明的新的局部变量就很有可能会复用过期局部变量的槽位从而达到节省资源的目的。[示例]下面的代码显示了局部变量表槽位的复用。在localvar1函数中局部变量a和b都作用到了函数末尾故b无法复用a所在的位置。而在localvar2函数中局部变量a在第16行时不再有效故局部变量b可以复用a的槽位(1个字)。我们看到localvar1有三个槽位我们看到localvar2中槽位1得到复用b复用了a的槽位局部变量的回收局部变量表中的变量也是重要的垃圾回收根节点只要被局部变量表中直接或间接引用的对象都是不会被回收的。因此理解局部变量表对理解垃圾回收也有一定帮助。publicclassLocalVarGCTest{//情况1publicvoidlocalvarGc1(){byte[]anewbyte[6*1024*1024];System.gc();}//情况2publicvoidlocalvarGc2(){byte[]anewbyte[6*1024*1024];anull;System.gc();}//情况3publicvoidlocalvarGc3(){{byte[]anewbyte[6*1024*1024];}System.gc();}//情况4publicvoidlocalvarGc4(){{byte[]anewbyte[6*1024*1024];}intc10;System.gc();}//情况5publicvoidlocalvarGc5(){localvarGc1();System.gc();}publicstaticvoidmain(String[]args){LocalVarGCTestinsnewLocalVarGCTest();ins.localvarGc4();}}上述代码中每一个localvarGc函数都分配了一块6MB的堆空间并使用局部变量引用这块空间。情况1在localvarGc1中在申请空间后立即进行垃圾回收很明显由于byte 数组被变量a引用因此无法回收这块空间。情况2在localvarGc2中在垃圾回收前先将变量a置为null,使byte数组失去强引用故垃圾回收可以顺利回收byte数组。情况3对于localvarGc3, 在进行垃圾回收前先使局部变量a失效虽然变量a已经离开了作用域但是变量a依然存在于局部变量表中并且也指向这块byte数组故byte数组依然无法被回收。情况4对于localvarGc4在垃圾回收之前不仅使变量a失效更是申明了变量c使变量c复用了变量a的字由于变量a此时被销毁故垃圾回收器可以顺利回收byte数组。情况5对于localvarGc5它首先调用了localvarGc1很明显在localvarGc1中 并没有释放byte数组但在localvarGc1返回后它的栈帧被销毁自然也包含了栈帧中的所有局部变量故byte数组失去引用在localvarGc5的垃圾回收中被回收。可以使用参数-XX:PrintGC执行上述几个函数在输出的日志中可以看到垃圾回收前后堆的大小进而推断byte数组是否被回收。下 面的输出是函数localvarGc4的运行结果:1.2.3.3 操作数栈操作数栈也是栈帧中重要的内容之一它主要用于保存计算过程的中间结果同时作为计算过程中变量临时的存储空间。操作数栈也是一个先进后出的数据结构只支持入栈和出栈两种操作。许多Java字节码指令都需要通过操作数栈进行参数传递。比如iadd指令它就会在操作数栈中弹出两个整数并进行加法计算计算结果会被入栈如图所示显示了iadd前后操作数栈的变化。publicstaticintadd(){inti10;intj20;intzij;returnz;}*步骤|指令|局部变量表|操作数栈|说明*-----|-----------|---------------|-------------|----------------*0||[]|[]|初始状态*1|bipush10|[]|[10]|压入常量10*2|istore_0|[a10]|[]|存储到变量a*3|bipush20|[a10]|[20]|压入常量20*4|istore_1|[a10,b20]|[]|存储到变量b*5|iload_0|[a10,b20]|[10]|加载变量a*6|iload_1|[a10,b20]|[10,20]|加载变量b*7|iadd|[a10,b20]|[30]|执行加法*8|istore_2|[a10,b20,c30]|[]|存储结果到c*9|iload_2|[a10,b20,c30]|[30]|加载返回值*10|ireturn|销毁|清空|返回30*publicstaticvoidtest(){inti0;ii;System.out.println(i);}*步骤|指令|i的值|操作数栈|说明*-----|-----------|-------|---------|------------------*0|iconst_0|-|[0]|压入常量0*1|istore_0|0|[]|初始化i0*2|iload_0|0|[0]|加载i的当前值(0)*3|iinc0,1|1|[0]|i自增为1栈不变*4|istore_0|0|[]|将栈顶的0存回i1.2.4 程序计数器线程私有是一块很小的内存空间。它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。它是程序控制流的指示器。本地方法栈 (Native Method Stack)与虚拟机栈作用非常相似区别在于虚拟机栈为执行 Java 方法服务而本地方法栈则为执行本地Native方法服务用 C/C 编写的方法。0iconst_01istore_02iload_03iinc0by16istore_07getstatic #2java/lang/System.out:Ljava/io/PrintStream;10iload_011invokevirtual #3java/io/PrintStream.println:(I)V14return程序计数器就是前面的数字1.3 执行引擎它负责执行字节码文件中的指令。解释器 (Interpreter)逐行读取、解释并执行字节码指令。优点是启动快缺点是执行速度相对较慢。即时编译器 (Just-In-Time Compiler, JIT)为了弥补解释器的慢JVM 会将运行频繁的“热点代码”如循环、高频方法编译成本地机器码并缓存起来存储在方法区下次执行时直接运行机器码极大提升效率。HotSpot JVM 的名字就来源于其强大的热点代码探测技术。垃圾回收器 (Garbage Collector, GC)执行引擎的一个重要组成部分它自动管理堆内存回收不再被使用的对象所占用的空间是 Java 内存自动管理的基石。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询