
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
Java编程开发语言随着互联网的不断发展而被越来越多的程序员掌握并应用到不同的软件开发项目之中,而本文我们就通过案例分析来简单了解一下,Java编程内存模型策略分析。
一个Java程序从程序编写到编译,编译到运行,运行到执行等过程来说,究竟是先入堆还是先入栈呢?
这个问题,其实我在看JavaHotSpot(TM)VM虚拟机相关知识的时候,一直有这样的个疑虑,但是其实这样的表述是不准确的,这需要结合编译原理相关的知识来具体分析。
按照编译原理的观点,从Java内存分配策略来看,程序运行时的内存分配有三种策略,其中:
静态存储分配:静态存储分配要求在编译时能知道所有变量的存储要求,指在编译时,就能确定每个数据在运行时的存储空间,因而在编译时就可以给他们分配固定的内存空间。这种分配策略要求程序代码中不允许有可变数据结构的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求。
栈式存储分配:栈式存储分配要求在过程的入口处必须知道所有的存储要求,也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的。和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,也就是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存。栈式存储分配按照先进后出的原则进行分配。
堆式存储分配:堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。
也就是说,在Java领域中,一个Java程序从程序编写到编译,编译到运行,运行到执行等过程来说,单纯考虑是先入堆还是入栈的问题,在这里得到了答案。
从整体上来看,Java内存模型主要考虑的事情基本与主存,线程本地内存,共享变量,变量副本,线程等概念息息相关,其中:
从主存与线程本地内存的关系来看:主存主要保存Java程序中的共享变量,其中主存不保存局部变量和方法参数列表;而线程本地内存主要保存Java程序中的共享变量的变量副本。
从线程与线程本地内存的关系来看:每个线程都会维护一个自己专属的本地内存,不同线程之间互相不可直接通信,其线程之间的通信就会涉及共享变量可见性的问题。
在Java内存模型中,一般来说主要提供volatile,synchronized,final以及锁等4种方式来保证变量的可见性问题,其中:
通过volatile关键词实现:利用volatile修饰声明时,变量一旦有更改都会被立即同步到主存中,当线程需要使用这个变量时,需要从主存中刷新到工作内存中。
通过synchronized关键词实现:利用synchronized修饰声明时,当一个线程释放一个锁,强制刷新工作内存中的变量到主存中,当另外一个线程需要使用此锁时,会强制重新载入变量值。
通过final关键词实现:利用final修饰声明时,变量一旦初始化完成,Java中的线程都可以看到这个变量。
通过JDK中锁实现:当一个线程释放一个锁,强制刷新工作内存中的变量到主存中,当另外一个线程需要使用此锁时,会强制重新载入变量值。
实际上,相比之下,Java内存模型还引入了一个工作内存的概念来帮助我们提升性能,而且JMM提供了合理的禁用缓存以及禁止重排序的方法,所以其核心的价值在于解决可见性和有序性。
其中,需要特别注意的是,其主存和工作内存的区别:
主存:可以在计算机内存模型说是物理内存,对应到Java内存模型来讲,是JavaHotSpot(TM)VM虚拟机中虚拟内存的一部分。
工作内存:在计算机内存模型内是指CPU缓存,一般是指寄存器,还有以及我们说的三层高速缓存策略中的L1/L2/L3层高级缓存;对应到Java内存模型来讲,主要是三层高速缓存Cache和寄存器。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请加danei0707学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。