java应用堆空间问题
今天突然想到一个问题,我们项目用到了一个ConstantService类,这个类在spring容器初始化时创建
View Code
1 import java.io.FileNotFoundException; 2 import java.io.IOException; 3 import java.net.URL; 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.Iterator; 7 import java.util.Map; 8 import java.util.Properties; 9 10 import org.apache.log4j.Logger; 11 import org.springframework.core.io.Resource; 12 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 13 import org.springframework.core.io.support.ResourcePatternResolver; 14 15 public class ConstantService { 16 17 private static final Logger log = Logger.getLogger(ConstantService.class); 18 19 private static Map<String, String> constantsMap = null; 20 private static String DEFAULT_FILENAME = "Constants.properties"; 21 private String configfile; 22 23 public void init() { 24 loadConstants(); 25 } 26 27 private boolean loadConstants() { 28 if (constantsMap == null) 29 constantsMap = new HashMap(); 30 boolean retFlag = true; 31 log.info("开始初始化常量配置!"); 32 URL files[] = genRealConfigFile(); 33 URL aurl[] = files; 34 int i = 0; 35 for (int j = aurl.length; i < j; ++i) { 36 URL strFileName = aurl[i]; 37 Properties props = new Properties(); 38 try { 39 props.load(strFileName.openStream()); 40 for (Iterator localIterator = props.entrySet().iterator(); localIterator 41 .hasNext();) { 42 Map.Entry entry = (Map.Entry) localIterator.next(); 43 if (constantsMap.containsKey((String) entry.getKey())) 44 log.error(LoggerUtils.format( 45 "常量初始化时,常量名[#1]重复。框架采用覆盖原则!", 46 new String[] { (String) entry.getKey() })); 47 constantsMap.put((String) entry.getKey(), (String) entry 48 .getValue()); 49 } 50 } catch (FileNotFoundException e) { 51 retFlag = false; 52 log.error(LoggerUtils.format("Can't find config file:[#1]", 53 new String[] { strFileName.getFile() })); 54 } catch (IOException e) { 55 retFlag = false; 56 log.error(LoggerUtils.format( 57 "Error when loading config file:[#1]", 58 new String[] { strFileName.getFile() })); 59 } 60 } 61 log.info(LoggerUtils.format("常量配置初始化完毕!共[#1]个常量", 62 new String[constantsMap.size()])); 63 log.info(constantsMap); 64 return retFlag; 65 } 66 67 private URL[] genRealConfigFile() { 68 String[] aryConfigFile = (String[]) null; 69 if (!(StringUtils.hasText(this.configfile))) 70 aryConfigFile = new String[] { DEFAULT_FILENAME }; 71 else 72 aryConfigFile = StringUtils.tokenizeToStringArray(this.configfile, 73 ","); 74 ArrayList tmpList = new ArrayList(); 75 String[] arrayOfString1 = aryConfigFile; 76 int i = 0; 77 for (int j = arrayOfString1.length; i < j; ++i) { 78 String strResource = arrayOfString1[i]; 79 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); 80 try { 81 Resource[] resources = resourcePatternResolver 82 .getResources(strResource); 83 for (int k = 0; k < resources.length; ++k) 84 tmpList.add(resources[k].getURL()); 85 } catch (Exception e) { 86 e.printStackTrace(); 87 } 88 } 89 URL[] ret = new URL[tmpList.size()]; 90 return ((URL[]) tmpList.toArray(ret)); 91 } 92 93 public static String getConstant(String strKey) 94 { 95 return StringUtils.trimText((String)constantsMap.get(strKey)); 96 } 97 98 public static Map<String, String> getConstants(String strPreFix) 99 { 100 if (!(StringUtils.hasText(strPreFix))) 101 return null; 102 103 Map retMap = null; 104 Iterator itrKey = constantsMap.keySet().iterator(); 105 while (itrKey.hasNext()) { 106 String strTmpKey = (String)itrKey.next(); 107 if (strTmpKey.startsWith(strPreFix + ".")) { 108 if (retMap == null) 109 retMap = new HashMap(); 110 111 retMap.put(strTmpKey.substring(strPreFix.length() + 1), (String)constantsMap.get(strTmpKey)); 112 } 113 } 114 115 return retMap; 116 } 117 118 public static Map getConstantsMap() { 119 return constantsMap; 120 } 121 122 public static void setConstantsMap(Map constantsMap) { 123 ConstantService.constantsMap = constantsMap; 124 } 125 126 public static String getDEFAULT_FILENAME() { 127 return DEFAULT_FILENAME; 128 } 129 130 public static void setDEFAULT_FILENAME(String default_filename) { 131 DEFAULT_FILENAME = default_filename; 132 } 133 134 public String getConfigfile() { 135 return configfile; 136 } 137 138 public void setConfigfile(String configfile) { 139 this.configfile = configfile; 140 } 141 }
1 <!-- 初始化加载文本 --> 2 <bean class="com.cvicse.jaf.utils.ConstantService" 3 init-method="init"> 4 <!-- 初始化和加载常量文件 --> 5 <property name="configfile" 6 value="constant/Constants*.properties" /> 7 </bean>
在项目的其它很多地方都用到了类似如下的代码
1 String jmsIp = ConstantService.getConstant("jmsIp"); 2 String uuapJmsUserName = ConstantService.getConstant("uuapJmsUserName"); 3 String uuapJmsPwd = ConstantService.getConstant("uuapJmsPwd");
我是这样理解的ConstantService这个类在spring容器初始化后单例模式实例化,且在spring容器存活期间一直持有,那么这个类在spring容器的生命周期里只会
加载一次,且一直被容器持有。
然后我又想,因为对象是保存在堆内存中的,也就是说整个项目会使用同一个堆,以前因为项目在导出excel数据过多时,而导致堆内存不足,手动设置过开发使用的tomcat生产使用的和websphere,jvm内存大小,如下:
tomcat
-Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=512m -XX:MaxPermSize=256m
Websphere
在应用程序服务器>server1>进程定义>Java虚拟机>配置里面设置初始堆大小和最大堆大小
而我重写一个带main方法的java类,run as Java Application,调用这个ConstantService的静态属性,并不会得到已经配置过的静态属性
然后我就想了是不是我们的jvm可以创建多个jvm实例,而整个tomcat就是一个jvm实例,我新创建的这个带main方法的类运行时也会唯一对应一个jvm实例,唯一对应自己的堆空间。
然后我查了下,百度知道上有个人的回答基本吻合了我的想法。
Java项目跟jvm进程数量没什么直接关系。通常我们用java 命令运行一个程序就会启动一个jvm进程,就是你所说的jvm实例。可以看看tomcat的启动脚本(非常复杂),但最终是通过一个java命令启动tomcat容器。webapp运行于tomcat容器基础之上,和tomcat同属于一个jvm进程是必然的。至于spring,容器的概念更多是逻辑上的,它仅仅是一个类(ApplicationContext,BeanFactory)的实例。web应用启动时加载一个WebApplicationContext实例,即我们所说的spring容器
追问
按你的意思理解 一个程序启动一个jvm实例,一个项目能保证在一个jvm里面吗
另外 如果一个tomcat加载n各项目 他们之间彼此调用(比如通过http访问),是不是跨jvm?
谢谢
回答
同一个项目可以部署在多台机器上,通过代理服务器转发请求给不同机器处理。这样就是个简单地web集群了。同一个tomcat下部署地应用自然是在一个jvm里。至于你说地通过http访问,其实只通过客户端通过http协议发起地,并不是服务器之间地调用关系。相当于客户端地两个请求
我使用