我的 effective java -- 6.消除过期的对象引用

本文探讨了在支持垃圾回收的语言中如何避免内存泄露问题,包括通过清除过期对象引用、使用WeakHashMap等方式来解决缓存和监听器导致的内存泄露。

 6.消除过期的对象引用

 

例子:

public class Stack {
		private Object[] elements;
		private int size = 0;
		private static final int DEFAULT_INITIAL_CAPACITY = 16;
		
		public Stack(){
			elements = new Object[DEFAULT_INITIAL_CAPACITY];
		}
		
		public void push(Object e){
			ensureCapacity();
			elements[size++] = e;
		}
		
		public Object pop(){
			if(size == 0){
				 throw new EmptyStackException();
			}
			return elements[--size];
		}
		
		private void ensureCapacity(){
			if(elements.length ==  size){
				 elements = Arrays.copyOf(elements,2 * size + 1);
			}
		}
}
 

 

在支持垃圾回收的语言中,内存泄露是很隐蔽的。如果一个对象的引用被无意识的保留起来了,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象。即时只有少量的几个对象引用被无意识的保留下来,也会有许许多多的对象呗排除在垃圾回收机制之外,从而对性能造成潜在的重大影响。

 

此类问题的修复方法:一旦对象引用已经过期,只需清空这些引用即可,程序会立即抛出NullPointerException异常。

消除引用最好的方法是让包含该引用的的变量结束其生命周期。

 

内存泄露的诱因:

1 只要类是自己管理内存,就应该警惕内存泄露问题。如例中的‘elements’ 

2  内存泄露来源于缓存,一旦你吧对象引用放到缓存中,很容易遗忘,导致长期存在于缓存中。

处理方法:可以使用WeakHashMap ,或者由一个后台线程(Timer或者ScheduledThreadPoolExcutor)来完成,或者也可爱给缓存增加新条目的时候进行清理

3源于监听器和其他回调的内存泄露。如果你实现一个API,客户端在这个API中注册回调,却没有显性的取消注册,会造成沉积。

 

 

内存泄露剖析工具:Heap Profiler

C:\Users\Zzh\.jdks\corretto-1.8.0_452\bin\java.exe -Dmaven.multiModuleProjectDirectory=D:\BaiduNetdiskDownload\118-仿天猫商城项目\2-源码资料\1-项目源码\3-源项目\TmallDemo-master -Djansi.passthrough=true -Dmaven.home=C:/Users/Zzh/.m2/wrapper/dists/apache-maven-3.6.0-bin/2dakv70gp803gtm5ve1ufmvttn/apache-maven-3.6.0 -Dclassworlds.conf=C:\Users\Zzh\.m2\wrapper\dists\apache-maven-3.6.0-bin\2dakv70gp803gtm5ve1ufmvttn\apache-maven-3.6.0\bin\m2.conf "-Dmaven.ext.class.path=D:\IntelliJ IDEA 2025.1\plugins\maven\lib\maven-event-listener.jar" "-javaagent:D:\IntelliJ IDEA 2025.1\lib\idea_rt.jar=58763" -Dfile.encoding=UTF-8 -classpath C:\Users\Zzh\.m2\wrapper\dists\apache-maven-3.6.0-bin\2dakv70gp803gtm5ve1ufmvttn\apache-maven-3.6.0\boot\plexus-classworlds-2.5.2.jar org.codehaus.classworlds.Launcher -Didea.version=2025.1 -Dexec.workingdir=D:/BaiduNetdiskDownload/118-仿天猫商城项目/2-源码资料/1-项目源码/3-源项目/TmallDemo-master "-Dexec.args=-classpath %classpath com.xq.tmall.TmallApplication" -Dexec.executable=C:\Users\Zzh\.jdks\corretto-1.8.0_452\bin\java.exe exec:exec [INFO] Scanning for projects... [WARNING] [WARNING] Some problems were encountered while building the effective model for com.xq.tmall:TmallDemo:jar:0.0.1-SNAPSHOT [WARNING] 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique: org.springframework.boot:spring-boot-starter-test:jar -> duplicate declaration of version (?) @ line 149, column 21 [WARNING] [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build. [WARNING] [WARNING] For this reason, future Maven versions might no longer support building such malformed projects. [WARNING] [INFO] [INFO] -----------------------< com.xq.tmall:TmallDemo >----------------------- [INFO] Building TmallDemo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- exec-maven-plugin:1.6.0:exec (default-cli) @ TmallDemo --- . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.6.RELEASE) 2025-06-30 19:21:27.540 INFO 5992 --- [ restartedMain] com.xq.tmall.TmallApplication : Starting TmallApplication on LAPTOP-T84T4BV3 with PID 5992 (started by Zzh in D:\BaiduNetdiskDownload\118-����è�̳���Ŀ\2-Դ������\1-��ĿԴ��\3-Դ��Ŀ\TmallDemo-master) 2025-06-30 19:21:27.542 DEBUG 5992 --- [ restartedMain] com.xq.tmall.TmallApplication : Running with Spring Boot v2.1.6.RELEASE, Spring v5.1.8.RELEASE 2025-06-30 19:21:27.542 INFO 5992 --- [ restartedMain] com.xq.tmall.TmallApplication : The following profiles are active: dev 2025-06-30 19:21:27.577 INFO 5992 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2025-06-30 19:21:27.949 ERROR 5992 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration.propertySourcesPlaceholderConfigurer at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:59) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:181) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:141) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:117) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:327) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:232) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:705) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:311) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at com.xq.tmall.TmallApplication.main(TmallApplication.java:13) [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_452] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_452] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_452] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_452] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.6.RELEASE.jar:2.1.6.RELEASE] Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.xq.tmall.config.datasource.DruidConfiguration] from ClassLoader [org.springframework.boot.devtools.restart.classloader.RestartClassLoader@3b7740c5] at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:507) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:404) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:389) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:447) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_452] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:738) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:679) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:647) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1518) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1023) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.addBeanTypeForNonAliasDefinition(BeanTypeRegistry.java:190) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.addBeanTypeForNonAliasDefinition(BeanTypeRegistry.java:157) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.addBeanType(BeanTypeRegistry.java:150) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.updateTypesIfNecessary(BeanTypeRegistry.java:138) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at java.util.Iterator.forEachRemaining(Iterator.java:116) ~[na:1.8.0_452] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.updateTypesIfNecessary(BeanTypeRegistry.java:133) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.BeanTypeRegistry.getNamesForType(BeanTypeRegistry.java:97) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:268) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:261) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:250) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:170) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:145) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:46) ~[spring-boot-autoconfigure-2.1.6.RELEASE.jar:2.1.6.RELEASE] ... 21 common frames omitted Caused by: java.lang.NoClassDefFoundError: javax/servlet/Filter at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_452] at java.lang.Class.privateGetDeclaredMethods(Class.java:2729) ~[na:1.8.0_452] at java.lang.Class.getDeclaredMethods(Class.java:2003) ~[na:1.8.0_452] at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:489) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] ... 43 common frames omitted Caused by: java.lang.ClassNotFoundException: javax.servlet.Filter at java.net.URLClassLoader.findClass(URLClassLoader.java:387) ~[na:1.8.0_452] at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_452] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[na:1.8.0_452] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_452] at org.springframework.boot.devtools.restart.classloader.RestartClassLoader.loadClass(RestartClassLoader.java:144) ~[spring-boot-devtools-2.1.6.RELEASE.jar:2.1.6.RELEASE] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_452] ... 47 common frames omitted 2025-06-30 19:21:27.954 WARN 5992 --- [ restartedMain] o.s.boot.SpringApplication : Unable to close ApplicationContext java.lang.IllegalStateException: Failed to introspect Class [com.xq.tmall.config.datasource.DruidConfiguration] from ClassLoader [org.springframework.boot.devtools.restart.classloader.RestartClassLoader@3b7740c5] at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:507) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:404) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:389) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:447) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_452] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:738) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:679) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:647) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1518) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:511) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:481) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:602) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:594) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1226) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE] at org.springframework.boot.SpringApplication.getExitCodeFromMappedException(SpringApplication.java:864) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.getExitCodeFromException(SpringApplication.java:852) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.handleExitCode(SpringApplication.java:839) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:790) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] at com.xq.tmall.TmallApplication.main(TmallApplication.java:13) [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_452] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_452] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_452] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_452] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.6.RELEASE.jar:2.1.6.RELEASE] Caused by: java.lang.NoClassDefFoundError: javax/servlet/Filter at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_452] at java.lang.Class.privateGetDeclaredMethods(Class.java:2729) ~[na:1.8.0_452] at java.lang.Class.getDeclaredMethods(Class.java:2003) ~[na:1.8.0_452] at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:489) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE] ... 26 common frames omitted Caused by: java.lang.ClassNotFoundException: javax.servlet.Filter at java.net.URLClassLoader.findClass(URLClassLoader.java:387) ~[na:1.8.0_452] at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_452] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[na:1.8.0_452] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_452] at org.springframework.boot.devtools.restart.classloader.RestartClassLoader.loadClass(RestartClassLoader.java:144) ~[spring-boot-devtools-2.1.6.RELEASE.jar:2.1.6.RELEASE] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_452] ... 30 common frames omitted [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.390 s [INFO] Finished at: 2025-06-30T19:21:28+08:00 [INFO] ------------------------------------------------------------------------ 进程已结束,退出代码为 0
07-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值