怎么做自己的彩票网站,电商运营要学多久,软件公司工资高吗,做网站的入门书籍文章目录 程序计数器栈堆方法区知识延申 -- 字符串常量池 程序计数器
并发情况下#xff0c;会发生线程之间的上下文切换#xff0c;当 线程1 的CPU时间片用完后#xff0c;需要程序计数器记录 线程1 的下一条JVM指令的地址#xff0c;等下一次 线程1 继续运行的时#x… 文章目录 程序计数器栈堆方法区知识延申 -- 字符串常量池 程序计数器
并发情况下会发生线程之间的上下文切换当 线程1 的CPU时间片用完后需要程序计数器记录 线程1 的下一条JVM指令的地址等下一次 线程1 继续运行的时才能从正确的位置开始继续执行
程序计数器是线程私有的 既 一个线程计数器 记录一个 线程 的指令位置
而且程序计数器是运行时数据区域唯一一个不存在内存溢出的区域
栈
线程是什么实际上可以理解为线程就是一个栈
线程调用方法 就是复制方法入栈的过程
方法入栈后就会形成栈帧
比如下面的一段代码
public class JvmDemo {public static void main(String[] args) {System.out.println(开始);func();System.out.println(结束);} public static void func(){}
}执行该程序会创建一个主线程然后main方法入栈示意图如下 接着mian方法执行到 func(); 就会复制一份 func 方法入栈如下 func方法执行完后出栈如下 最后mian方法再出栈
我们说线程可以简单的认为就是栈所以也很明显栈是线程私有的
栈的容量有限如果我们不断调用方法入栈就会导致栈溢出 比如递归时没有递归出口
栈分为 虚拟机栈 和 本地方法栈
可以简单理解为 -入栈的方法由 java 语言编写 的为虚拟机栈 -入栈的方法由 C语言编写 的为本地方法栈
Object类中有很多本地方法比如反射中用到的 public final native Class? getClass(); 添加了native 关键字使用C语言编写为了能直接对接操作系统
关于栈的几个问题
垃圾回收是否涉及栈内存 不涉及 因为栈帧执行完就会自动出栈无需垃圾回收栈内存是否分配越大越好吗错误 物理内存大小一定栈内存越大能同时纯在的栈就会越少既 线程数会越少方法内的局部变量是否是线程安全的 是线程安全的线程调用方法是复制方法入栈所以每个线程都有自己的方法副本也就有了自己的局部变量副本所以在操作时不会受到其他线程的干扰
堆
堆 – 存储对象实例
比如下面代码
public class JvmDemo {public static void main(String[] args) {Person person new Person();}
}class Person{}其在内存中的模型如下 person引用存在main方法的栈帧中而person实例对象存在于堆区中
堆区是所有线程共享的 比如
public class JvmDemo {public static void main(String[] args) {Person person new Person();Thread thread01new Thread(()-{Person person01 new Person();});thread01.start();}
}class Person{}则内存模型如下为了突出重点省略 thread01 引用和实例对象 在内存中的展示以及 thread01.start(); 的调用过程 堆的内存有限不能无限创建对象实例否者会堆内存溢出
因此JVM存在堆区的垃圾回收机制清除垃圾对象垃圾对象 可以简单定义为没有引用指向的实例对象
比如
Person person new Person;
person new Person;此时就没有引用指向第一个new出来的对象那么它就会被垃圾回收
存在堆区中的对象实例是线程间共享的对象中的 全局变量 需要考虑线程安全问题
比如
public class JvmDemo {public static void main(String[] args) throws InterruptedException {Person person new Person();Thread thread01new Thread(()-{for (int i0;i100000;i){person.money;}});thread01.start();for (int i0;i100000;i){person.money;}thread01.join();System.out.println(person.money);}
}
class Person{public int money0;
}输出的结果不一定是200000
方法区
方法区 – 存储 类信息 和 静态变量、方法
在 jdk 1.8之前方法区存在于JVM内存中其实现方法被称为 永久代jdk 1.8及之后方法区从JVM内存移出到本地内存其实现方法被称为 元空间
方法区是线程共享的因此多个线程修改同一个类的静态变量的时候同样存在线程安全问题比如
public class JvmDemo {public static void main(String[] args) throws InterruptedException {Thread thread01new Thread(()-{for (int i0;i100000;i){Person.money;}});thread01.start();for (int i0;i100000;i){Person.money;}thread01.join();System.out.println(Person.money);}
}
class Person{public static int money0;
}输出结果同样不一定是200000此处建议先学习一下什么是静态变量
方法区同样存在内存溢出的问题
知识延申 – 字符串常量池
JVM中还有一个特殊又重要的区域就是 字符串常量池StringTable可以参考我的另外一篇博客
【Java 基础】你真的会用 String 吗