`
gavin.zheng
  • 浏览: 20268 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类
最新评论

static的常驻内存

阅读更多
对于配置等经常使用的对象,而且基本上在使用的时候很少修改的,我们可以让它常驻内存.

如何常驻内存,这是我们最关心的.这就是static的使用技巧,
照例以配置文件来讨论,请看以下代码

class Config{

private static HashMap expMap = new HashMap();

//装载personMap,为简单不使用singleton模式
public Config(){
   //读取配置文件,并装载进expMap
   loadExpMap();
}

public static Object getExpMap(String key){
   synchronized(this){
       return expMap.get(key);
     }
}

public static HashMap setExpMap(String key, Object o){
   synchronized(this){
       expMap.put(key, o);
     }
   return expMap.clone();
}

public static Object removeExpMap(String key){
   synchronized(this){
       expMap.remove(key);
     }
   return expMap.clone();
}

}



注意以下2点
所有的调用方法如果不是确定已经被同步,误必使用synchronized,当然,你说用rw锁也行^^
如果需要返回,为其他线成或者其他此对象消费者着想, 请clone,



顺带说下,关于JNDL之类的动态装载工厂方法是如何实现的.
JNDI的动态装载方式在ResourcesManager类中,使用的是类似我这样的static常驻内存方式,不过他使用的是WeakHashMap做的引用, 也就是说当不使用这些工厂对象时候,里面的引用对象会被自动回收

不要轻易用它!!太高级了,贵啊,一般情况我们用不起^^, 它会对每个加入其中的对象产生线成去检测回收的


回各位大大的话
1为什么需要同步,涉及到多线城同步是必须的,只是看你的使用方式问题而已, 比如有位仁兄说性能消耗太高,这不是问题的问题.  如果不是static, 比如说cache 然后类似使用servlet装载进app做全局的话, 也有点这个的意思, 当然,这个时候由于可能读写巨大,所以就只能尽量使用rw锁了,性能上优化点.
2为什么clone,既然是一个公共对象,你把引用的值返回出去你放心??可能会被外面的资源通过这个引用修改它的,所以不要直接返回.
3这是个简单的全局对象的例子,到底里面是什么无所谓,所以不存在什么set get的问题


分享到:
评论
22 楼 frenchmay 2008-12-21  
private static HashMap expMap = new HashMap();
如果改为private static final Map expMap = new HashMap()
会怎么样??不知道楼主考虑过没有

另外
public static HashMap setExpMap(String key, Object o){ 
    synchronized(this){ 
        expMap.put(key, o); 
      } 
    return expMap.clone(); 

这样做是否成本太高,是否可以尝试单独创建一个方法返回clone对象

另外这个clone是否能够把里面的键值也clone吗??
21 楼 starse7en77 2008-12-20  
fjlyxx 写道
提个建议,这个类你是否要考虑到单例,个人觉得要保护好你的STATIC 还有同步呢?
再则,怎么方法都没有抛出异常,如果指定KEY找不到VALUE是不是返回NULL呢?如果这样外部是否还要判断,你这块的逻辑需要补充。
哦 对了 最好在方法里面加final 避免恶意修改,反正你也不要继承的。
个人意见,仅供参考。


第一句话好深 . 还真不易理解 . 呵呵
20 楼 starse7en77 2008-12-20  
static 其实并没有那么恐怖 ...
对读取数据用同步很是不懂
其实 , 这里用单例就够了 , 几乎可以忽略同步的影响 .
还有不明白的是 , 为什么装载配置在构造函数中 , 而读取数据却用static方法 ? 没有什么是不可能 .
19 楼 jhaij 2008-12-18  
gavin.zheng 写道

public static HashMap setExpMap(String key, Object o){
   synchronized(this){
       expMap.put(key, o);
     }
   return expMap.clone();
}

public static Object removeExpMap(String key){
   synchronized(this){
       expMap.remove(key);
     }
   return expMap.clone();
}

}



支持timerri 的看法, 这里set方法确实用synchronized 不太好
18 楼 netfork 2008-11-30  
gavin.zheng 写道
对于配置等经常使用的对象,而且基本上在使用的时候很少修改的,我们可以让它常驻内存.

如何常驻内存,这是我们最关心的.这就是static的使用技巧,
照例以配置文件来讨论,请看以下代码

class Config{

private static HashMap expMap = new HashMap();

//装载personMap,为简单不使用singleton模式
public Config(){
   //读取配置文件,并装载进expMap
   loadExpMap();
}

public static Object getExpMap(String key){
   synchronized(this){
       return expMap.get(key);
     }
}

public static HashMap setExpMap(String key, Object o){
   synchronized(this){
       expMap.put(key, o);
     }
   return expMap.clone();
}

public static Object removeExpMap(String key){
   synchronized(this){
       expMap.remove(key);
     }
   return expMap.clone();
}

}



注意以下2点
所有的调用方法如果不是确定已经被同步,误必使用synchronized,当然,你说用rw锁也行^^
如果需要返回,为其他线成或者其他此对象消费者着想, 请clone,



顺带说下,关于JNDL之类的动态装载工厂方法是如何实现的.
JNDI的动态装载方式在ResourcesManager类中,使用的是类似我这样的static常驻内存方式,不过他使用的是WeakHashMap做的引用, 也就是说当不使用这些工厂对象时候,里面的引用对象会被自动回收

不要轻易用它!!太高级了,贵啊,一般情况我们用不起^^, 它会对每个加入其中的对象产生线成去检测回收的


回各位大大的话
1为什么需要同步,涉及到多线城同步是必须的,只是看你的使用方式问题而已, 比如有位仁兄说性能消耗太高,这不是问题的问题.  如果不是static, 比如说cache 然后类似使用servlet装载进app做全局的话, 也有点这个的意思, 当然,这个时候由于可能读写巨大,所以就只能尽量使用rw锁了,性能上优化点.
2为什么clone,既然是一个公共对象,你把引用的值返回出去你放心??可能会被外面的资源通过这个引用修改它的,所以不要直接返回.
3这是个简单的全局对象的例子,到底里面是什么无所谓,所以不存在什么set get的问题




楼主这样的代码,实在是太误导新手了吧~~~~
怎么看,也看不出synchronized和clone是干啥用的?请问LZ,下面的情况,是不是可能有问题啊?

1、关于synchronized
第一个线程搞到第20行执行完,挂起;
第二个线程搞18~20行,然后也挂起;
第一个线程醒过来,继续搞21行,此时,第二个线程中的“o”对象已经弄进expMap中了呀,由此,这里的同步想不明白是干么的啊?
2、关于HashMap的clone
HashMap的clone是浅表副本:并不复制键和值本身。
所以,你光把HashMap给clone了,里面的东东没有clone,不是一样可以修改里面的东西吗?所谓的引用修改,不是照样没避免吗?

综上,感觉本文没有价值啊?

17 楼 gembler 2008-11-30  
<div class='quote_title'>gavin.zheng 写道</div>
<div class='quote_div'><br/><br/>
<pre name='code' class='java'>class Config{

private static HashMap expMap = new HashMap();

public static Object getExpMap(String key){
   synchronized(this){
       return expMap.get(key);
     }
}

}
</pre>
<br/><br/></div>
<p> </p>
<p>这里你猜猜会发生什么事情~static method里synchronized(this)..........</p>
<p> </p>
<div class='quote_title'>niveko 写道</div>
<div class='quote_div'>你为什么不使用private static Map expMap = new ConcurrentHashMap();<br/>这样不是减少你同步的问题,性能也好些吗?<br/></div>
<p> </p>
<p>niveko说得对,java.util.concurrent就可以了。</p>
<p> </p>
16 楼 fjlyxx 2008-11-30  
timerri 的克隆做法我觉得不应该做在这一层。因为这层提供了修改和获取两个函数,你就是克隆了也不能起到什么作用,如果在上一层只提供一个返回MAP的接口 这时候不允许外部程序修改MAP 倒是可以考虑使用克隆。

再则,修改全局变量的时候你应该让修改的线程拥有令牌,只允许它操作,这个过程是一个短暂的过程,如果这个时候你拿给别人一个脏数据它也是没有用的。这种情况是无法避免的,要么你就让要获取的线程等待,要么就直接给它异常,让他下次再试。

个人意见,仅供参考
15 楼 fjlyxx 2008-11-30  
提个建议,这个类你是否要考虑到单例,个人觉得要保护好你的STATIC 还有同步呢?
再则,怎么方法都没有抛出异常,如果指定KEY找不到VALUE是不是返回NULL呢?如果这样外部是否还要判断,你这块的逻辑需要补充。
哦 对了 最好在方法里面加final 避免恶意修改,反正你也不要继承的。
个人意见,仅供参考。
14 楼 lifethinker 2008-11-26  
timerri 写道
为什么不要修改了再clone,因为这样就使内存中存在了2个功能完全相同的副本。而其中一个无用。这样的使用方式只在很少的情景下才需要出现。我很奇怪的是为什么要对外返回一个内部对象的副本而不是提供一个查询内部对象的方法?


返回对象的副本是保证线程安全的一种方式,也就是CopyOnWrite,它主要用于写(或更新)操作比较少的情况下,主要的好处是客户端不需要同步访问,主要缺点是下一次更新时客户端得不到最新的数据。直接返回对象当然可以,它和CopyOnWrite的优缺点刚好相反,缺点是客户端访问时需要同步,优点是客户端可以得到最新的数据。
13 楼 zhajie 2008-11-26  

没有必要用synchronized吧,

现在不都是java.util.concurrent时代了吗?
12 楼 lc4ever 2008-11-25  
<code>
public static Object getExpMap(String key){ 
    synchronized(this){ 
        return expMap.get(key); 
      } 
}
</code>
这个能编译过去吗?
11 楼 gavin.zheng 2008-11-25  
怎么这么多人批判~~   只是说的一个方式而已,  需要全局有很多方法 比如web中放app等.  随便说说而已
10 楼 xixix2004 2008-11-24  
其实都没问题。LZ选择案例要慎重阿。。。。
9 楼 chbest 2008-11-04  
很是折腾.
已然是读配置文件.
写个方法暴漏get
把set隐藏起来就可以了
又不需要支持代码修改了,重读配置文件
8 楼 timerri 2008-11-04  
哦?我语气比较生硬,听着不舒服??

1.这种配置信息本来就是键值对的方式的,为什么MAP不合适?多吃你1K内存,还是耗费的起的。
如果耗费的起,那也用不着谈什么性能了,这里说map不合适不是内存上的,而是查找时间上的。想必你应该知道查询和直接索引的速度区别吧!

2.修改了再clone有什么问题呢?人家那个方法是要讲一个值put进map去,然后还要把这个map返回。
之所以返回一个clone的,是因为如果直接返回原map的引用,外界就有可能修改了这个公共配置map里的对象。
先clone了再修改,那不是要把两个都修改一遍吗?有什么好的?看看clone的实现吧,有那么恐怖吗?

为什么不要修改了再clone,因为这样就使内存中存在了2个功能完全相同的副本。而其中一个无用。这样的使用方式只在很少的情景下才需要出现。我很奇怪的是为什么要对外返回一个内部对象的副本而不是提供一个查询内部对象的方法?


3.synchronized是不能滥用,可是楼主的文章里没有滥用,你在下边说这个东西是性能杀手,是暗含着楼主的用法是滥用吗?如果不是的话,那么synchronized滥用的危害是另一个话题,又为什么拿到这篇帖子下边来说?

config一般来讲是一个读(get)多写(put)少的对象。楼主的例子在读(get)中加了synchronized,那么如果有多个线程同时读config会怎么样呢?就会被互相同步!synchronized用在这里是不合适的。


如果还有不舒服,只有请克服..

7 楼 WhisperXD 2008-11-04  
yyjn12 写道
timerri 写道
真正常驻内存又常用的东西不要用map!直接定义到类里。

另外,不要修改了再clone,这是个坏习惯,宁愿clone了再修改!!无必要的话,根本不要去clone.

synchronized一定不能滥用。这东西是典型的性能杀手。根据场景选择合适的同步方式才是必要的。




这种配置信息本来就是键值对的方式的,为什么MAP不合适?多吃你1K内存,还是耗费的起的。

修改了再clone有什么问题呢?人家那个方法是要讲一个值put进map去,然后还要把这个map返回。
之所以返回一个clone的,是因为如果直接返回原map的引用,外界就有可能修改了这个公共配置map里的对象。
先clone了再修改,那不是要把两个都修改一遍吗?有什么好的?看看clone的实现吧,有那么恐怖吗?


synchronized是不能滥用,可是楼主的文章里没有滥用,你在下边说这个东西是性能杀手,是暗含着楼主的用法是滥用吗?如果不是的话,那么synchronized滥用的危害是另一个话题,又为什么拿到这篇帖子下边来说?

synchronized里的代码块执行的仅仅是个get或是put到map里去,还是不会有什么大问题的吧。

总之看到你的回复,觉得很不舒服。


没有大问题是因为你没碰到过真正这东西形成的性能瓶颈。。当然大部分情况下你爱怎么写怎么写,企业应用或许全部synchronized也没人理你。。
6 楼 yyjn12 2008-11-04  
timerri 写道
真正常驻内存又常用的东西不要用map!直接定义到类里。

另外,不要修改了再clone,这是个坏习惯,宁愿clone了再修改!!无必要的话,根本不要去clone.

synchronized一定不能滥用。这东西是典型的性能杀手。根据场景选择合适的同步方式才是必要的。




这种配置信息本来就是键值对的方式的,为什么MAP不合适?多吃你1K内存,还是耗费的起的。

修改了再clone有什么问题呢?人家那个方法是要讲一个值put进map去,然后还要把这个map返回。
之所以返回一个clone的,是因为如果直接返回原map的引用,外界就有可能修改了这个公共配置map里的对象。
先clone了再修改,那不是要把两个都修改一遍吗?有什么好的?看看clone的实现吧,有那么恐怖吗?


synchronized是不能滥用,可是楼主的文章里没有滥用,你在下边说这个东西是性能杀手,是暗含着楼主的用法是滥用吗?如果不是的话,那么synchronized滥用的危害是另一个话题,又为什么拿到这篇帖子下边来说?

synchronized里的代码块执行的仅仅是个get或是put到map里去,还是不会有什么大问题的吧。

总之看到你的回复,觉得很不舒服。
5 楼 timerri 2008-11-04  
真正常驻内存又常用的东西不要用map!直接定义到类里。

另外,不要修改了再clone,这是个坏习惯,宁愿clone了再修改!!无必要的话,根本不要去clone.

synchronized一定不能滥用。这东西是典型的性能杀手。根据场景选择合适的同步方式才是必要的。

4 楼 niveko 2008-11-04  
# private static HashMap expMap = new HashMap(); 

你为什么不使用private static Map expMap = new ConcurrentHashMap();
这样不是减少你同步的问题,性能也好些吗?

才看到你的HashMap的定义都没有使用接口哦


n台机器的话建议你做个memcahced集中管理吧,本地存一份,memcahced也有一份,更新的同时更新memcahced。获取的时候先找本地的,没有的话在去memcahced中找
3 楼 chbest 2008-11-04  
n台机器怎么同步?

相关推荐

    常见的八种导致 APP 内存泄漏的问题1

    这是因为 Activity 的类对象是静态的,一旦加载,就会在 APP 运行时一直常驻内存,因此如果类对象不卸载,其静态成员就不会被垃圾回收。 例如,在某个 Activity 中定义了一个静态变量:`private static Activity ...

    ios-block的局部变量和全局变量和static的静态变量联系.zip

    全局Block则常驻内存。 局部变量是在函数或方法内部定义的变量,它们的作用域仅限于定义它们的代码块。一旦该代码块执行完毕,局部变量就会被销毁。如果在Block中使用了局部变量,那么Block会捕获这个变量的一个...

    c++堆栈等关键词的总结

    register 存储类型声明为 register 的变量在由内存调入到 CPU 寄存器后,则常驻在 CPU 的寄存器中,因此访问 register 变量将在很大程度上提高效率,因为省去了变量由内存调入到寄存器过程中的好几个指令周期。...

    C#全局hook实例

    为了使Hook在全局范围内生效,它必须在主线程或者一个常驻内存的进程中运行,并且需要确保在程序退出时正确地释放资源,以防止内存泄漏或系统资源占用过高。 总的来说,全局Hook在调试、监控、自动化测试等领域有...

    获取正在运行进程的实例

    通过读取`/proc/&lt;pid&gt;/status`文件,可以获取进程的内存使用情况,如`VmSize`表示虚拟内存大小,`VmRSS`表示常驻集大小(实际物理内存占用)。 对于Java开发者,可以使用`java.lang.management`包中的`...

    PHP 单例模式解析和实战

    这意味着PHP在语言级别上无法让某个对象常驻内存,这与Java等编译型语言不同。在Java中,单例会一直存在于整个应用程序的生命周期里,而PHP中所有变量都是页面级的,每次页面执行时都会重新建立新的对象。因此,在...

    (完整版)烟草计算机试题.doc

    内部命令常驻内存,而外部命令则是在运行时从磁盘加载到内存中。 6. **计算机寻址方式**: - 寻址方式决定了处理器如何定位内存中的数据。常见的寻址方式包括**直接寻址**、**间接寻址**和**变址寻址**等。 #### ...

    9种Java单例模式详解(推荐)

    饿汉式避免了线程同步问题,但是缺点是相比接下来的静态内部类而言,这种方法比静态内部类多了内存常驻,容易造成内存浪费,也未达到延迟加载的效果。 ```java public class Singleton{ private static Singleton ...

    技术文档JAVAspring

    【Java Spring 技术文档概览】 ...GET请求常用于获取资源,数据...String对象常驻于常量池,便于重复使用和节省内存。在Spring框架中,字符串常用于构建SQL语句、配置文件等,理解其特性和不可变性对于优化代码至关重要。

    事业编制计算机专业考试试题及答案.pdf

    6. **DOS内部命令与外部命令**:内部命令是DOS操作系统的一部分,常驻于内存,可以直接执行;外部命令则是单独的可执行文件,位于硬盘或其他存储介质上。 7. **计算机寻址方式**:计算机寻址方式包括直接寻址、间接...

    PHP单例模式是什么 php实现单例模式的方法

    这意味着PHP不能像编译型语言(如Java)那样让对象常驻内存。在PHP中,无论是全局变量还是类的静态成员,都是页面级的,每次页面被执行时,都会重新建立新的对象,并在页面执行完毕后被清空。因此,在PHP中,单例...

    PHP单例模式定义与使用实例详解

    单例模式是软件设计模式中一种特殊的编程方式,其核心思想在于确保一个...然而,单例模式的使用需要小心处理,因为单例常驻内存可能会导致内存泄漏或状态难以管理等问题。在设计时,应当考虑单例的适用场景,避免滥用。

    php定期拉取数据对比方法实例

    例如,使用基于Swoole的框架EasySwoole,可以实现常驻内存的定时任务,这大大提高了任务执行的效率。EasySwoole提供了一个Crontab模块,使得定时任务的创建和管理变得更加简单。以下是一个使用EasySwoole创建定时...

    我的android学习记录

    ### 我的Android学习记录 ... - 如果实例化的对象长时间不被利用,会常驻内存,消耗内存资源。 以上就是从给定的文件中提炼出来的相关知识点,涵盖了Android开发中的多个方面,希望对读者有所帮助。

    贪玩php面试题.docx

    21. **static与global**:`static`关键字用于在函数内部保留变量的状态,每次调用不会重新初始化;`global`用于在函数内部引用全局变量。 22. **重写protected方法**:子类可以重写父类的protected方法,无特殊限制...

    PHP的静态方法与普通方法用法实例分析

    4. **内存常驻**:静态方法和静态属性会一直存在直到程序执行结束或者被显式地清理。这意味着静态方法和静态属性占用的内存不会随着对象的销毁而释放,而普通方法和非静态属性则会在对象的生命周期结束时被释放。 5...

    practice:保留一些通用方法

    4. **性能优化**:由于通用方法常驻内存,多次调用时不会产生额外的实例化开销。 在实践中,创建一个名为`practice-master`的项目,可能包含了多个这样的通用方法类,每个类专注于一个特定领域的通用功能,比如字符...

    Android的广播Receiver动态注册和静态注册示例

    &lt;action android:name="com.yourpackage.STATIC_ACTION" /&gt; ``` 静态注册的BroadcastReceiver可以在任何时间接收广播,无论应用程序是否运行,甚至在设备重启后。这使得静态注册非常适合处理重要的系统级事件,...

Global site tag (gtag.js) - Google Analytics