java程序员必须知道的内存知识-应用层

简介: 1.volatile可见性,使用volatile修饰的变量可以立刻被其它线程读取到,经常会被用到多线程同步的关键变量上,像aqs的state。因为CPU在访问主存需要大约十几个时钟周期,为了提高cpu的效率便有了高速缓存,当数据被加载到高速缓存时,其它核并不能第一时间看到。内存屏障,最常见的就是双检锁了,我们简单的new对象在虚拟机内部其实需要很多操作,虚拟机为了提高性能,会对我们代码进行重排,使用volatile可以保证变量在被编译时的顺序性。

1.volatile


可见性,使用volatile修饰的变量可以立刻被其它线程读取到,经常会被用到多线程同步的关键变量上,像aqs的state。

image.png

因为CPU在访问主存需要大约十几个时钟周期,为了提高cpu的效率便有了高速缓存,当数据被加载到高速缓存时,其它核并不能第一时间看到。内存屏障,最常见的就是双检锁了,我们简单的new对象在虚拟机内部其实需要很多操作,虚拟机为了提高性能,会对我们代码进行重排,使用volatile可以保证变量在被编译时的顺序性。


image.png


volatile、synchronized、final都会影响虚拟机的指令重排,会通过指令集中的loadload、storestore、loadstore、storeload四个内存屏障实现。总结来说,volatile的作用有3个,编译重排(虚拟机优化重排)、指令重排(cpu指令重排)、内存重排(高速缓存脏读)


2.缓存行


缓存行是为了解决cpu访问主存时间长的问题,之前文章有过介绍。https://segmentfault.com/a/11...https://segmentfault.com/a/11...

缓存行友好

因为缓存行会存储多份数据,所以有了缓存行一致性协议,但一致性协议有一定成本,如果缓存行被共享,又频繁修改,会导致性能下降。解决办法也很简单,就是让一个缓存行只有一条数据,保证数据独享。java8提供了jdk.internal.vm.annotation.Contended注解,在类上加注解后,虚拟机会自动做缓存行填充。

缓存行抖动

因为缓存行大小有限,所以缓存行只能缓存部分数据,因为缓存行采用映射的方式选择缓存的数据,如下图,如果ABCD四个数据都映射到上面的一个行里,当我们要访问A时,要把A加载进来,这时我们要访问B,要把缓存行清空,再加载B,这时如果还需要访问A,又得把B清掉,加载A,这就是缓存行抖动。

image.png


这是一个常见的例子,数组x和数组y同时映射到一个缓存行,当访问x[i]时,要加载x到缓存行,访问y[i]时又需要把y加载到缓存行,常见的解决办法也比较简单,就是扩充数组大小,让x和y无法映射到一个缓存行。


image.png


3.内存池


堆内存由jvm替我们申请和回收,但是垃圾回收也是我们系统的瓶颈之一,所以有些时候为了提高性能或者其他原因,我们也会使用堆外内存,例如netty,netty的堆外内存池使用的就是类似slab的机制实现的,如果有兴趣可以看看源码,这里就不细说了。


4.java引用


强引用

强引用就是我们平时使用的Object a = new Object()。如果一个对象具有强引用,那垃圾回收器就不会回收这个new Object()

软引用

如果一个对象只有软引用,在内存充足时垃圾回收器就不会回收它;如果内存空间不足了,就会回收软引用应用的对象。软引用的回收会根据上次gc剩余内存,软引用上次访问的时间动态调整,就是上次访问的时间越久,上次gc剩余内存越少,越容易被回收。

弱引用

如果一个对象只有弱引用,只要触发gc就会被回收(包括年轻代gc)。

虚引用

虚引用的get方法会直接返回null,虚引用的作用主要是对象在被回收时可以通过虚引用通知到程序,对象被回收了。





image.pngimage.pngimage.pngimage.pngimage.png

相关文章
|
13天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
18天前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
42 9
|
24天前
|
缓存 easyexcel Java
Java EasyExcel 导出报内存溢出如何解决
大家好,我是V哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。以下是V哥整理的解决该问题的一些常见方法,包括分批写入、设置合适的JVM内存、减少数据对象的复杂性、关闭自动列宽设置、使用Stream导出以及选择合适的数据导出工具。此外,还介绍了使用Apache POI的SXSSFWorkbook实现百万级别数据量的导出案例,帮助大家更好地应对大数据导出的挑战。欢迎一起讨论!
139 1
|
3天前
|
SQL 存储 Java
面向 Java 程序员的 SQLite 替代品
SQLite 是轻量级数据库,适用于小微型应用,但其对外部数据源支持较弱、无存储过程等问题影响了开发效率。esProc SPL 是一个纯 Java 开发的免费开源工具,支持标准 JDBC 接口,提供丰富的数据源访问、强大的流程控制和高效的数据处理能力,尤其适合 Java 和安卓开发。SPL 代码简洁易懂,支持热切换,可大幅提高开发效率。
|
8天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
29 6
|
12天前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
33 2
|
13天前
|
存储 安全 Java
什么是 Java 的内存模型?
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)规范的一部分,它定义了一套规则,用于指导Java程序中变量的访问和内存交互方式。
35 1
|
15天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
21天前
|
IDE Java 程序员
C++ 程序员的 Java 指南
一个 C++ 程序员自己总结的 Java 学习中应该注意的点。
20 5
|
19天前
|
存储 运维 Java
💻Java零基础:深入了解Java内存机制
【10月更文挑战第18天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
26 1