JAVA的缓存应用
Java内存缓存工具GuavaLoadingCache使用解析

Java内存缓存⼯具GuavaLoadingCache使⽤解析这篇⽂章主要介绍了Java内存缓存⼯具Guava LoadingCache使⽤解析,⽂中通过⽰例代码介绍的⾮常详细,对⼤家的学习或者⼯作具有⼀定的参考学习价值,需要的朋友可以参考下⼀、Guava介绍Guava是Google guava中的⼀个内存缓存模块,⽤于将数据缓存到JVM内存中。
实际项⽬开发中经常将⼀些公共或者常⽤的数据缓存起来⽅便快速访问。
Guava Cache是单个应⽤运⾏时的本地缓存。
它不把数据存放到⽂件或外部服务器。
如果不符合需求,可以选择Memcached、Redis等⼯具。
⼆、代码⽰例1. POM引⼊<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>28.1-jre</version></dependency>2. 封装⼯具类package com.soyoung.ad.engine.util;import mon.cache.*;import lombok.extern.slf4j.Slf4j;import java.util.Map;import java.util.concurrent.TimeUnit;/*** 功能描述** @author 马振全 2020/1/13 16:18*/@Slf4jpublic class CacheManager {/** 缓存项最⼤数量 */private static final long GUAVA_CACHE_SIZE = 100000;/** 缓存时间:天 */private static final long GUAVA_CACHE_DAY = 10;/** 缓存操作对象 */private static LoadingCache<Long, String> GLOBAL_CACHE = null;static {try {GLOBAL_CACHE = loadCache(new CacheLoader<Long, String>() {@Overridepublic String load(Long key) throws Exception {// 处理缓存键不存在缓存值时的处理逻辑return "";}});} catch (Exception e) {log.error("初始化Guava Cache出错", e);}}/*** 全局缓存设置** 缓存项最⼤数量:100000* 缓存有效时间(天):10*** @param cacheLoader* @return*/private static LoadingCache<Long, String> loadCache(CacheLoader<Long, String> cacheLoader) throws Exception { LoadingCache<Long, String> cache = CacheBuilder.newBuilder()//缓存池⼤⼩,在缓存项接近该⼤⼩时, Guava开始回收旧的缓存项.maximumSize(GUAVA_CACHE_SIZE)//设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程⾥⾯不定期维护).expireAfterAccess(GUAVA_CACHE_DAY, TimeUnit.DAYS)// 设置缓存在写⼊之后设定时间后失效.expireAfterWrite(GUAVA_CACHE_DAY, TimeUnit.DAYS)//移除监听器,缓存项被移除时会触发.removalListener(new RemovalListener<Long, String>() {@Overridepublic void onRemoval(RemovalNotification<Long, String> rn) {//逻辑操作}})//开启Guava Cache的统计功能.recordStats().build(cacheLoader);return cache;}/*** 设置缓存值* 注: 若已有该key值,则会先移除(会触发removalListener移除监听器),再添加** @param key* @param value*/public static void put(Long key, String value) {try {GLOBAL_CACHE.put(key, value);} catch (Exception e) {log.error("设置缓存值出错", e);}}/*** 批量设置缓存值** @param map*/public static void putAll(Map<? extends Long, ? extends String> map) {try {GLOBAL_CACHE.putAll(map);} catch (Exception e) {log.error("批量设置缓存值出错", e);}}/*** 获取缓存值* 注:如果键不存在值,将调⽤CacheLoader的load⽅法加载新值到该键中** @param key* @return*/public static String get(Long key) {String token = "";try {token = GLOBAL_CACHE.get(key);} catch (Exception e) {log.error("获取缓存值出错", e);}return token;}/*** 移除缓存** @param key*/public static void remove(Long key) {try {GLOBAL_CACHE.invalidate(key);log.error("移除缓存出错", e);}}/*** 批量移除缓存** @param keys*/public static void removeAll(Iterable<Long> keys) {try {GLOBAL_CACHE.invalidateAll(keys);} catch (Exception e) {log.error("批量移除缓存出错", e);}}/*** 清空所有缓存*/public static void removeAll() {try {GLOBAL_CACHE.invalidateAll();} catch (Exception e) {log.error("清空所有缓存出错", e);}}/*** 获取缓存项数量** @return*/public static long size() {long size = 0;try {size = GLOBAL_CACHE.size();} catch (Exception e) {log.error("获取缓存项数量出错", e);}return size;}}三、使⽤总结1. 移除机制guava做cache时候数据的移除分为被动移除和主动移除两种。
java redis 缓存分页实现原理

java redis 缓存分页实现原理Java Redis缓存是一种用于在Web应用程序中提高数据访问性能的技术。
它通过将常用的数据存储在内存中,以便更快地访问和获取,从而减少了对数据库的访问。
分页是Web应用程序中常见的功能之一,它允许用户在列表或表格中浏览数据,并按页查看数据,以减少数据量和提高用户体验。
Java Redis缓存的分页实现原理是,将查询的结果集划分为多个页,并将每个页的数据存储在Redis缓存中,以供后续的访问和查询。
下面将详细介绍Java Redis缓存分页的实现原理。
1.将查询结果集分页:在数据库查询之后,将结果集按照每页显示的数量划分为多个页,例如每页显示10条数据,将结果集分为若干个包含10条数据的页。
这样可以方便后续的分页访问和查询。
2.将每页的数据存储到Redis缓存中:对于每个分页的数据,将其存储到Redis缓存中。
可以使用Redis 的数据结构Hash或List来存储每页的数据。
对于Hash结构,可以使用页号作为Key,对应的数据作为Value,将所有页的数据存储到一个Hash中。
对于List结构,可以使用一个List来存储所有的分页数据,每个分页数据作为一个元素。
通过使用Redis缓存,可以提高分页的访问速度和性能。
3.使用Redis缓存进行分页查询:当用户请求分页数据时,首先从Redis缓存中获取对应页的数据。
如果缓存中存在该页的数据,则直接返回给用户;如果缓存中不存在该页的数据,则从数据库中查询该页的数据,并存储到Redis缓存中,以供后续的查询和访问。
4.缓存失效和更新:为了保证数据的实时性,需要处理缓存的失效和更新问题。
当用户修改或删除数据时,需要更新对应页的数据缓存,或者将所有缓存的数据进行失效处理,以保证数据的一致性。
可以通过监听数据的修改和删除操作,在数据库操作完成后,更新或失效对应的缓存数据。
5.缓存过期时间设置:为了控制内存使用和避免缓存数据过时,可以设置缓存数据的过期时间。
Java中的分布式缓存框架有哪些

Java中的分布式缓存框架有哪些随着互联网应用的快速发展,分布式缓存已经成为了提高系统性能和扩展性的关键技术之一。
在Java开发领域,也涌现了许多优秀的分布式缓存框架。
本文将介绍几个Java中常用的分布式缓存框架,并分析它们的特点和适用场景。
一、EhcacheEhcache是一个开源的Java缓存框架,被广泛应用于各种Java应用中。
它提供了基于内存和磁盘的缓存机制,支持分布式部署,能够满足大规模应用的缓存需求。
Ehcache具有轻量级、易于使用和快速的特点,适合用于小型和中型的应用系统。
二、RedisRedis是一种高性能的内存数据存储系统,支持多种数据结构,可以用作分布式缓存的解决方案。
Redis提供了持久化和复制机制,可以实现高可用性和数据持久化。
同时,Redis还具有丰富的功能,如发布订阅、事务管理等,使得它不仅可以作为缓存系统,还可以用于其他用途,如消息队列等。
Redis适用于各种规模的应用系统。
三、MemcachedMemcached是一个简单的高性能分布式内存对象缓存系统。
它使用键值对的方式存储数据,提供了多种API,支持分布式部署。
Memcached具有高速的读写性能和可扩展性,通常被用于缓存数据库查询结果、页面内容等。
它适用于大规模应用和高并发场景,但需要注意的是,Memcached不提供数据持久化功能。
四、HazelcastHazelcast是一个基于Java的开源分布式缓存框架,它提供了分布式数据结构和集群管理功能。
Hazelcast采用了集中式架构,能够实现多节点之间的数据共享和同步。
它具有简单易用的特点,并提供了多种数据结构和并发算法的支持。
Hazelcast适用于构建复杂的分布式应用系统。
五、CaffeineCaffeine是一个在Java中最受欢迎的缓存库之一,它提供了高性能、无锁的内存缓存解决方案。
Caffeine采用了分片策略来管理缓存对象,提供了各种缓存策略和配置选项,可以根据实际需求进行灵活配置。
Java本地缓存工具之LoadingCache的使用详解

Java本地缓存⼯具之LoadingCache的使⽤详解⽬录前⾔环境依赖代码演⽰⼀下总结前⾔在⼯作总常常需要⽤到缓存,⽽redis往往是⾸选,但是短期的数据缓存⼀般我们还是会⽤到本地缓存。
本⽂提供⼀个我在⼯作中⽤到的缓存⼯具,该⼯具代码为了演⽰做了⼀些调整。
如果拿去使⽤的话,可以考虑做成注⼊Bean对象,看具体需求了。
环境依赖先添加maven依赖<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1.1-jre</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.5.2</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>代码不废话,上代码了。
package ai.guiji.csdn.tools;import cn.hutool.core.thread.ThreadUtil;import mon.cache.*;import lombok.extern.slf4j.Slf4j;import java.text.MessageFormat;import java.util.Map;import java.util.concurrent.TimeUnit;import java.util.function.Consumer;import java.util.function.Function;import java.util.stream.LongStream;/** @Author 剑客阿良_ALiang @Date 2021/12/30 17:57 @Description: 缓存⼯具 */@Slf4jpublic class CacheUtils {private static LoadingCache<Long, String> cache;/*** 初始化缓存⽅法** @param totleCount 缓存池上限* @param overtime 超时时间* @param unit 时间单位* @param handleNotExist 处理不存在key⽅法* @param handleRemove 移除主键消费*/private static void initCache(Integer totleCount,Integer overtime,TimeUnit unit,Function<Long, String> handleNotExist,Consumer<Long> handleRemove) {cache =CacheBuilder.newBuilder()// 缓存池⼤⼩.maximumSize(totleCount)// 设置时间对象没有被读/写访问则对象从内存中删除.expireAfterWrite(overtime, unit)// 移除监听器.removalListener(new RemovalListener<Long, String>() {@Overridepublic void onRemoval(RemovalNotification<Long, String> rn) { handleRemove.accept(rn.getKey());}}).recordStats().build(new CacheLoader<Long, String>() {@Overridepublic String load(Long aLong) throws Exception {return handleNotExist.apply(aLong);}});("初始化缓存");}/*** 存⼊缓存** @param key 键* @param value 值*/public static void put(Long key, String value) {try {("缓存存⼊:[{}]-[{}]", key, value);cache.put(key, value);} catch (Exception exception) {log.error("存⼊缓存异常", exception);}}/*** 批量存⼊缓存** @param map 映射*/public static void putMap(Map<Long, String> map) {try {("批量缓存存⼊:[{}]", map);cache.putAll(map);} catch (Exception exception) {log.error("批量存⼊缓存异常", exception);}}/*** 获取缓存** @param key 键*/public static String get(Long key) {try {return cache.get(key);} catch (Exception exception) {log.error("获取缓存异常", exception);return null;}}/*** 删除缓存** @param key 键*/public static void removeKey(Long key) {try {cache.invalidate(key);} catch (Exception exception) {log.error("删除缓存异常", exception);}}/*** 批量删除缓存** @param keys 键*/public static void removeAll(Iterable<Long> keys) {try {cache.invalidateAll(keys);} catch (Exception exception) {log.error("批量删除缓存异常", exception);}}/** 清理缓存 */public static void clear() {try {cache.invalidateAll();} catch (Exception exception) {log.error("清理缓存异常", exception);}}/*** 获取缓存⼤⼩** @return 长度*/public static long size() {return cache.size();}public static void main(String[] args) {initCache(Integer.MAX_VALUE,10,TimeUnit.SECONDS,k -> {("缓存:[{}],不存在", k);return "";},x -> ("缓存:[{}],已经移除", x));System.out.println(size());LongStream.range(0, 10).forEach(a -> put(a, MessageFormat.format("tt-{0}", a)));System.out.println(cache.asMap());ThreadUtil.sleep(5000);LongStream.range(0, 10).forEach(a -> {System.out.println(get(a));ThreadUtil.sleep(1000);});System.out.println(cache.asMap());ThreadUtil.sleep(10000);System.out.println(cache.asMap());}}代码说明1、在初始化loadingCache的时候,可以添加缓存的最⼤数量、消逝时间、消逝或者移除监听事件、不存在键处理等等。
Java中的缓存技术

Java中的缓存技术缓存技术在软件开发中起着至关重要的作用。
它可以提高系统性能、降低对底层资源的访问频率,从而减轻服务器负载并改善用户体验。
在Java开发中,有许多可供选择的缓存技术。
本文将介绍几种常见的Java缓存技术,以及它们的应用场景和原理。
一、内存缓存内存缓存是最常见的缓存技术之一,它将数据保存在内存中,以提高读取速度。
在Java中,可以使用集合框架中的Map接口的实现类来实现内存缓存,如HashMap、ConcurrentHashMap等。
这些类提供了快速的Key-Value存储,通过Key快速查找对应的Value,以实现快速访问缓存数据。
内存缓存适用于数据读取频繁但不经常更新的场景,例如字典数据、配置信息等。
需要注意的是,内存缓存的容量是有限的,当缓存数据超过容量限制时,需要采取一些策略来处理,如LRU(最近最少使用)算法将最久未访问的数据移出缓存。
二、分布式缓存分布式缓存是一种将数据存储在多台服务器节点上的缓存技术。
Java中有多种分布式缓存框架可供选择,如Redis、Memcached等。
这些框架提供了高性能、可扩展的分布式缓存服务,可以在集群中存储大量的数据,并提供分布式缓存的管理和查询接口。
分布式缓存适用于需要同时服务大量客户端并具有高并发读写需求的场景,例如电商网站的商品信息、社交网络的用户数据等。
通过将数据存储在多台服务器上,可以提高系统的可用性和扩展性。
三、页面缓存页面缓存是将网页内容保存在缓存中,以减少对数据库或后端服务的访问频率,从而提高页面的加载速度。
在Java中,可以通过使用Web服务器或反向代理服务器的缓存功能,例如Nginx、Varnish等,来实现页面缓存。
页面缓存适用于内容相对静态或者不经常变化的场景,例如新闻网站的文章、博客网站的页面等。
通过将网页内容保存在缓存中,可以避免每次请求都重新生成页面,大大提高响应速度和系统的并发能力。
四、数据库缓存数据库缓存是将数据库查询结果保存在缓存中,以减少对数据库的频繁查询,提高系统的响应速度和并发能力。
Java中常用缓存Cache机制的实现

Java中常用缓存Cache机制的实现Java 中常用缓存Cache机制的实现所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。
这样做可以减少系统开销,提高系统效率。
Java 中常用缓存Cache机制的实现缓存主要可分为二大类:一、通过文件缓存,顾名思义文件缓存是指把数据存储在磁盘上,不管你是以XML格式,序列化文件DAT格式还是其它文件格式;二、内存缓存,也就是实现一个类中静态Map,对这个Map进行常规的增删查.代码如下:1. packagelhm.hcy.guge.frameset.cache;2.3. importjava.util.*;4.5. //Description:管理缓存6.7. //可扩展的功能:当chche到内存溢出时必须清除掉最早期的一些缓存对象,这就要求对每个缓存对象保存创建时间8.9. publicclassCacheManager{10. privatestaticHashMapcacheMap=newHashMap();11.12. //单实例构造方法13. privateCacheManager(){14. super();15. }16. //获取布尔值的.缓存17. publicstaticbooleangetSimpleFlag(Stringkey){18. try{19. return(Boolean)cacheMap.get(key);20. }catch(NullPointerExceptione){21. returnfalse;22. }23. }24. publicstaticlonggetServerStartdt(Stringkey){25. try{26. return(Long)cacheMap.get(key);27. }catch(Exceptionex){28. return0;29. }30. }31. //设置布尔值的缓存32. publicsynchronizedstaticbooleansetSimpleFlag(Stringkey,boolea nflag){33. if(flag&&getSimpleFlag(key)){//假如为真不允许被覆盖34. returnfalse;35. }else{36. cacheMap.put(key,flag);37. returntrue;38. }39. }40. publicsynchronizedstaticbooleansetSimpleFlag(Stringkey,longse rverbegrundt){41. if(cacheMap.get(key)==null){42. cacheMap.put(key,serverbegrundt);43. returntrue;44. }else{45. returnfalse;46. }47. }48.49.50. //得到缓存。
hutool缓存原理

Hutool是一个Java工具库,它提供了许多实用的功能和工具类,包括缓存管理。
然而,Hutool 本身并不提供独立的缓存框架或实现,而是使用了其他流行的缓存技术来实现其缓存功能。
具体来说,Hutool可以与以下常见的缓存技术集成:
1.Caffeine:Caffeine是一种基于Java的高性能内存缓存库。
Hutool中的CacheUtil类可以
与Caffeine集成,提供方便易用的缓存管理功能。
2.Ehcache:Ehcache是一个广泛使用的开源Java缓存框架。
Hutool中的CacheUtil类可以
与Ehcache集成,使用Ehcache实现缓存功能。
3.Redis:Redis是一种流行的内存数据结构存储系统,也可以用作缓存。
Hutool中的
CacheUtil类可以与Redis集成,使用Redis作为分布式缓存。
Hutool的缓存原理主要依赖于所选择的具体缓存技术的实现。
它提供了统一的API和封装,使使用者可以轻松地在应用程序中使用缓存功能。
根据所选的缓存技术,Hutool会将数据存储在内存中或者通过与外部缓存服务器进行通信来实现缓存操作。
需要注意的是,Hutool只是作为工具库提供了对缓存技术的封装和简化,并没有重新实现缓存技术本身。
因此,深入了解所选缓存技术的原理和特性,以及与Hutool的集成方式,将有助于更好地理解Hutool的缓存功能。
java. cache 用法

Java 中的缓存(Cache)是一种提高应用程序性能的技术,它通过在内存中存储经常访问的数据,避免了频繁地访问速度较慢的数据源(如数据库或文件)。
在Java 中,有许多内置的缓存实现,如`java.util.Cache`和`java.util.ConcurrentMap`等。
以下是一个简单的Java 缓存用法示例:1. 首先,导入所需的缓存类:```javaimport java.util.Cache;import java.util.ConcurrentMap;```2. 创建一个缓存实例:```javaCache<String, String> cache = new ConcurrentMap<>();```这里,我们使用`ConcurrentMap`作为缓存实现。
它可以保证在高并发场景下的性能表现。
3. 向缓存中添加数据:```javacache.put("key1", "value1");cache.put("key2", "value2");```4. 从缓存中获取数据:```javaString value1 = cache.get("key1");String value2 = cache.get("key2");```5. 删除缓存中的数据:```javacache.remove("key1");```6. 检查缓存中是否包含某个键:```javaboolean containsKey = cache.containsKey("key1"); ```7. 获取缓存中的所有键:```javaSet<String> keys = cache.keySet();```8. 获取缓存中的所有值:```javaCollection<String> values = cache.values();```9. 清除缓存:```javacache.clear();```10. 关闭缓存:```javacache.invalidate();```此外,Java 还提供了`java.util.expiringmap`类,它可以在缓存中设置过期时间,从而在数据不再需要时自动删除。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
当物理内存吃紧的情况下,会产生大量的页入,页出动作, 当物理内存吃紧的情况下,会产生大量的页入,页出动作,从而降低系统运行速度
再来看看任务管理器
总数: 总数:RAM物理内存总大小 物理内存总大小 可用数:当前RAM内存还剩余多少 可用数:当前 内存还剩余多少 系统缓存: 系统缓存:指的是系统共享内存使用量
•
• System.gc();其实并不一定立即触发垃圾回收。 只是告诉系统现在该进行垃圾回收了。 • JVM的垃圾回收一种自动的处理机制。 • 垃圾回收太频繁会对系统造成一定的压力, 因为要遍历所有的内存区域。
基本缓存的使用
• 为什么使用缓存 • JAVA集合类的应用(HashMap) • JAVA单例
注意:所以我们在给Java程序分配内存时是分不到2G空间的
存放具体的Classes、 Jar信息
JVM内存分配管理
• • • • • JVM如何管理内存 永久存储区(Permanent Space):永久存储区是JVM的驻留内存,用于存放JDK 自身所携带的Class,Interface的元数据。 堆空间(The Heap Space):JAVA对象的出生,成长,死亡都在这个区域完成;堆 空间又分为养老区和新生区。 新生区(Young (New) generation space):新生区的作用包括JAVA对象的创建和 从JAVA对象中筛选出能进入养老区的JAVA对象。 伊甸园(Eden space):JAVA对空间中的所有对象在此出生,该区的名字因此而 得名。也即是说当你的JAVA程序运行时,需要创建新的对象,JVM将在该区为 你创建一个指定的对象供程序使用。创建对象的依据即是永久存储区中的元 数据。 幸存者0区(Survivor 0 space)和幸存者1区(Survivor1 space):当伊甸园的 控件用完时,程序又需要创建对象;此时JVM的垃圾回收器将对伊甸园区进 行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁工作。 同时将伊甸园中的还有其他对象引用的对象移动到幸存者0区。如果0区域也 没有空间了就会向1区移动。 养老区(Tenure (Old) generation space):用于保存从新生区筛选出来的JAVA 对象。
Application 2GB
用于程序存放代码,数据,堆栈,自由存储区
Windows System 2GB
共享内存,所有进程都用到的内存区域
操作系统规定:一个应用程序所能承载的最大寻址内存 是2GB(可以通过配置改变到3GB),因为主要是为了预留 一部分给操作系统使用,叫做共享内存区。 所以虽然一个程序理论上可以访问4GB内存,但是实际 上只能分配2GB的空间。
JAVA内存体系介绍
• • • • • 操作系统的内存使用和管理 JVM内存的分类 JVM内存参数设置及作用 垃圾回收机制 内存实时状态查询
操作系统的内存使用和管理
• Windows内存使用 • 虚拟内存是Windows管理所有可用内存的方式。 • Windows 32位为每个进程分配了4G的虚拟地址空间(用 于表示该进程有这么多的空间可用),4G是由于操作系 统+CPU是32位的,寻址空间就只有2的32次方,因此得 出4G的存储空间。 • Windows操作系统默认会给程序和系统预留2G的内存寻 址空间;我们可以通过配置将应用程序的最大内存配置 到3G。 • 4G配置 但电脑显示最多3.5内存 。因为:xp/vista 32bit 在安装4G内存后会分配其中部分内存作为设备保留的内 存地址。 • 64位就不存在4GB空间的束缚了。
垃圾回收机制
• 首先当启动J2EE应用服务器时,JVM随之启动,并将JDK的类和接口,应用服务器运行时需要的类和接口以 及J2EE应用的类和接口定义文件也及 编译后的Class文件或JAR包中的Class文件装载到JVM的永久存储区。在 伊甸园中创建JVM,应用服务器运行时必须的JAVA对象,创建 J2EE应用启动时必须创建的JAVA对象;J2EE应 用启动完毕,可对外提供服务。 JVM在伊甸园区根据用户的每次请求创建相应的JAVA对象,当伊甸园的空间不足以用来创建新JAVA对象的时 候,JVM的垃圾回收器执行对伊甸园区的垃 圾回收工作,销毁那些不再被其他对象引用的JAVA对象(如果 该对象仅仅被一个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类 推),并 将那些被其他对象所引用的JAVA对象移动到幸存者0区。 如果幸存者0区有足够控件存放则直接放到幸存者0区;如果幸存者0区没有足够空间存放,则JVM的垃圾回 收器执行对幸存者0区的垃圾回收工作,销毁那些不 再被其他对象引用的JAVA对象(如果该对象仅仅被一 个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对 象 所引用的JAVA对象移动到幸存者1区。 如果幸存者1区有足够控件存放则直接放到幸存者1区;如果幸存者0区没有足够空间存放,则JVM的垃圾回 收器执行对幸存者0区的垃圾回收工作,销毁那些不 再被其他对象引用的JAVA对象(如果该对象仅仅被一 个没有其他对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并将那些被其他对 象 所引用的JAVA对象移动到养老区。 如果养老区有足够控件存放则直接放到养老区;如果养老区没有足够空间存放,则JVM的垃圾回收器执行 对养老区区的垃圾回收工作,销毁那些不再被其他对象引 用的JAVA对象(如果该对象仅仅被一个没有其他 对象引用的对象引用的话,此对象也被归为没有存在的必要,依此类推),并保留那些被其他对象所引用 的 JAVA对象。如果到最后养老区,幸存者1区,幸存者0区和伊甸园区都没有空间的话,则JVM会报告 “JVM堆空间溢出 (ng.OutOfMemoryError: Java heap space)”,也即是在堆空间没有空间来创建对 象。 这就是JVM的内存分区管理,相比不分区来说;一般情况下,垃圾回收的速度要快很多;因为在没有必要 的时候不用扫描整片内存而节省了大量时间。 通常大家还会遇到另外一种内存溢出错误“永久存储区溢出(ng.OutOfMemoryError: Java Permanent Space)”。
JAVA缓存体系及应用
2010.10.27
目录
• • • • • • 带着问题来,带着答案走 JAVA内存体系介绍 基本缓存的使用 缓存框架的介绍 内存溢出状况分析 内存检查工具的使用
问题
• JVM内存的分配原理? • JVM启动的时候如何正确的设置内存参数? • JVM内存是不是越大越好? • 什么情况下大家用到了缓存处理,很好的 解决了问题? • 缓存框架帮我们解决哪些问题,为什么要 使用缓存框架? • 你是如何进行内存溢出检查的?
JVM内存分类
• 系统级内存分配 • JVM的内存分配机制其实也是基于操作系统 分配机制 • JVM最大的内存在win32下是2G • JVM的内存使用情况实际被分为:JVM虚拟 机、JAVA程序的字节码(classes)、系统内存 空间Native Heap(主要用于存放线程和一些 系统级的对象和操作)、JAVA内存Java Heap(真正的存放Java Object 的内存区域)
•
•
JAVA所有管理的内存 堆空间(Java Heap Space)
伊甸园区(eden)
永久内存区域 (Permanent): 存放Classes、 Jar等数据
养老区(Tenured) (其实可以看作是”终极”幸 存者)
幸存者区0(survivor0) From
幸存者区1(survivor1) To
JVM内存参数设置
Permagnent 空间 Java Heap Space空间 Extend Virtual (永久区虚拟 内存) Extend Virtual (养老区虚拟内 存) Extend Virtual (幸存者区虚拟 内存)
Permagnet (永久区)
Tenured (养老区)
Enden (伊甸园)
Application 2GB
用于程序存放代码,数据,堆栈,自由存储区
Windows System 2GB
共享内存,所有进程都用到的内存区域
Jvm
Permanet
Native Heap
Java Heap
System lib
JAVA程序本身使用的内存区域
JNI的调用 存放线程、系统变量、 一些类似Runtime的操 作
Survivor0 (幸存者0)
Survivor0 (幸存者1)
-XX:MaxPermSize
-Xmx(最大内存配置) -Xms(最小内存配置,初始养老区+年轻区)
-XX:PermSize -XX:MaxNewSize(最大年轻区大小) -XX:NewSize(年轻区大小) -XX:SurvivorRatio (设置年轻代中Eden区与Survivor区的大小比值) -XX:NewRatio (设置年轻代(包括Eden和两个Survivor区)与年老代的比值)
所以我们可以得出2个程序的最大使用内存是:2G(共享内存)+2*2G(程序内存)=6G
为什么我的电脑是2G内存,但是在系统可以使用超过2G的内存空间,大概有 4G!
页面文件
• 以上情况是由于页面文件控制的。 • 这里很容易混淆一个概念,认为以上windows磁盘用来充当内 存的叫做虚拟内存,其实windows管理的内存都叫做虚拟内存。 所以虚拟内存是:RAM(物理内存)+页面文件(磁盘内存) • 页面文件即当内存不够时系统会拿出一部分硬盘空间来充当内 存使用,当内存占用完时,电脑就会自动调用硬盘来充当内存, 以缓解内存的紧张。比如:你的机器有2G内存,当使用的内存 超过2G时,超过的部分就会将硬盘上的文件映射成内存来使用。 • 按照这样逻辑我们不难得出只要虚拟内存够大,我们就可以无 限制的使用,不过考虑到性能这也是不切实际的。 • 以上只是很浅显的一个理解,其实Windows虚拟内存的管理是 一个比较复杂的处理过程,由于windows的多任务机制,再配 合虚拟内存,其实windows运行的程序所占用的内存是远远超 过可分配内存的。