Flyweight Pattern
use sharing to support large unmbers of fine-grained objects efficiently(使用共享对象可有效地支持大量的细粒度的对象)
例子
“三哥,厂商人员已经定位出了,OutOfMemory内存溢出,没查到有内存泄漏的情况,现 在还在跟踪……是突然暴涨的,都是在繁忙期出现问题的……”
内存溢出对Java应用来说实在是太平常了,有以下两种可能。
● 内存泄漏
无意识的代码缺陷,导致内存泄漏,JVM不能获得连续的内存空间。
● 对象太多
代码写得很烂,产生的对象太多,内存被耗尽。现在的情况是没有内存泄漏,那只有一 种原因——代码太差把内存耗尽。
系统厂商提供的分析报告,报告中指出:内存 突然由800MB飙升到1.4GB,新的对象申请不到内存空间,于是出现OutOfMemory,同时报 告中还列出宕机时刻内存中的对象,其中SignInfo类的对象就有400MB。
“三哥,这是很正常的,这么大的访问量,产生出这么多的SignInfo对象也是应该的,内 存中有这么多对象并不表示这些对象正在被使用呀,估计很大一部分还没有被回收而已,垃 圾回收器什么时候回收内存中的对象这是不确定的。你看,并发200多个,这可是并发数量……”
public class SignInfo {
private String key;
private String id;
private String subject;
private String location;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
public class SignInfoFactory {
private static HashMap<String,SignInfo> pool=new HashMap<String,SignInfo>();
public static SignInfo getSignInfo(String key){
SignInfo result=null;
if(!pool.containsKey(key)){
System.out.println(key+"-------------建立对象,并放到池中");
result=new SignInfo();
pool.put(key, result);
}else{
result=pool.get(key);
System.out.println(key+"---------------直接从池中取");
}
return result;
}
}
小知识
在对象池中,对象一旦产生,必然有一个唯一的、可访问的状态标志该对象,而 且池中的对象声明周期是由池容器决定,而不是由使用者决定的。
以String类型作为外部状态到对象池取对象,而为什么不抽取出俩个属性,例如id和location放到一个类中,然后以这个类作为外部状态,重写equals方法和hashcode方法(如果把一个对象作为Map类的键值,一定要确保重写了equals和hashCode方法, 否则会出现通过键值搜索失败的情况,例如map.get(object)、map.contains(object)等会返回失败的结果。)
这样做的后果是效率降低,因为外部状态最好以java基本类型作为标志,例如String,int等,可以大幅度提升效率。
public class Client {
public static void main(String[] args) {
String state1="sub1shanghai1";
String state2="sub1shanghai2";
String state3="sub1shanghai2";
SignInfoFactory.getSignInfo(state1);
SignInfoFactory.getSignInfo(state2);
long start=System.currentTimeMillis();
for(int i=0;i<100000;i++){
SignInfoFactory.getSignInfo(state3);
}
long end=System.currentTimeMillis();
System.out.println("total time:"+(end-start)+"ms");
}
}
其他问题还有线程安全,性能平衡等等,需要经验,这个东西只是提供一个方向,需要是还是实际开发。
不得不说这是个好东西,但是实际中,需要考虑的东西很多,这个为了解决一些连接问题根据底层硬件以及环境而做出的最好行动,还是需要看背景和实际问题。
我是菜鸟,我在路上。