`
躁动的绵羊
  • 浏览: 95914 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

讨论:单例和静态方法的深入讨论

阅读更多
    常在论坛上看见一些有关单例模式、静态类、静态方法缺点的讨论,说得最多的无非是使用static,破坏了面向对象的多态性,建议除非确定了该对象不会被扩展,否则不要使用单例模式、静态方法等。其中,举例最多的是:辅助类可采用单例、静态方法

     确实,我在开发中,看见的基本都是如此。但我一直有点疑问,今天在这提出,希望JE上兄弟讨论下:

    辅助类使用静态方法就一定好吗?我觉得可能也会存在如下问题:

    1.如果类中属性或方法是static的,那么在该类被装载到方法区时,是要分配内存的。那如果是static的,是不是表示该类(非对象)永远不会被垃圾收集了呢?从而占用一定的内存空间,如果这样的类多的话,那JVM的可使用内存不是会很少?既然这样,又何必用静态方法呢?(我不太确定含有静态字段或方法的类是否会被垃圾收集器收集
   
    2. 问题1一出现,则会衍生出问题2来,即由于加载到方法区中的类型都保持着一个对加载该类的类加载器的引用,既然类不能被垃圾收集,从而则一定会造成其对应的类加载器也不会被垃圾收集,这样,又会出现许多类加载不能被垃圾收集,不是更占有JVM内存空间了吗?
由于Java的安全性特点,加载不同包下的类的加载器一定不会是同一个对象吧。这个我不确定)。

    基于以上问题,希望JE兄弟赏脸,讨论下。

    先贴出我的观点:辅助类采用单例或静态天方法也不一定是最完美的。使用单例、静态的目的就是为了节省JVM内存,如果一个辅助类用的概率不是特别大,难道还应该向大部分人建议那样使用单例或静态吗?不应该了吧。







分享到:
评论
25 楼 yeswoyaofei 2011-01-10  
看看 《深入java虚拟机》那里有你要的答案
24 楼 mercyblitz 2011-01-10  
aabcc 写道
躁动的绵羊 写道
aabcc 写道
imacback 写道
aabcc 写道
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。


是这样吗?没有任何引用的时候就会被GC掉,跟加载他的CLASSLOADER没关系吧。


// The classes loaded by this class loader.  The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private Vector classes = new Vector();





   又出现分支了:到底是类先被卸载还是该类的转载类(classLoader)先被卸载呢?
   我一直这样认为的:只有类被GC了,则就没有对它的classLoader对象的引用了,于是classLoader就会被GC
  


class 是被 classLoader 引用的, class 没引用 classLoader。

一个 实例是否被 GC 跟 实例里面的 成员 是否被 GC 没关系。

你这种理解我表示很费解。

退一百步说,假如你的 成员是 弱引用 或者 软引用,成员被 GC了,对你的实例 是否被GC 没有判定上的影响,你的实例 还是 照 GC算法来 判定是否 入GC队列。



当调用ClassLoader#defineClass方法时,会释放前面一个版本的Class!
23 楼 aabcc 2011-01-10  
躁动的绵羊 写道
aabcc 写道
imacback 写道
aabcc 写道
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。


是这样吗?没有任何引用的时候就会被GC掉,跟加载他的CLASSLOADER没关系吧。


// The classes loaded by this class loader.  The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private Vector classes = new Vector();





   又出现分支了:到底是类先被卸载还是该类的转载类(classLoader)先被卸载呢?
   我一直这样认为的:只有类被GC了,则就没有对它的classLoader对象的引用了,于是classLoader就会被GC
  


class 是被 classLoader 引用的, class 没引用 classLoader。

一个 实例是否被 GC 跟 实例里面的 成员 是否被 GC 没关系。

你这种理解我表示很费解。

退一百步说,假如你的 成员是 弱引用 或者 软引用,成员被 GC了,对你的实例 是否被GC 没有判定上的影响,你的实例 还是 照 GC算法来 判定是否 入GC队列。
22 楼 躁动的绵羊 2011-01-10  
aabcc 写道
imacback 写道
aabcc 写道
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。


是这样吗?没有任何引用的时候就会被GC掉,跟加载他的CLASSLOADER没关系吧。


// The classes loaded by this class loader.  The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private Vector classes = new Vector();





   又出现分支了:到底是类先被卸载还是该类的转载类(classLoader)先被卸载呢?
   我一直这样认为的:只有类被GC了,则就没有对它的classLoader对象的引用了,于是classLoader就会被GC
  
21 楼 aabcc 2011-01-10  
imacback 写道
aabcc 写道
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。


是这样吗?没有任何引用的时候就会被GC掉,跟加载他的CLASSLOADER没关系吧。


// The classes loaded by this class loader.  The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private Vector classes = new Vector();


20 楼 imacback 2011-01-10  
aabcc 写道
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。


是这样吗?没有任何引用的时候就会被GC掉,跟加载他的CLASSLOADER没关系吧。
19 楼 aabcc 2011-01-10  
按我的理解,ClassLoader中,如果调用了 defineClass后就不能在该 ClassLoader中remove了

前面几位高手都说能卸载,求教卸载类的方法...

按我的理解,被ClassLoader装载过的类应该是有被ClassLoader中不可操作的强引用所引用,只有在classLoader本身被GC时,被该CLASSLOADER装载过的CLASS才有可能被GC(还要排除ClassLoader以外没有任何强引用去引用该class)

如果我理解错了,求批。

18 楼 zhongrenmeng 2011-01-10  
躁动的绵羊 写道
mercyblitz 写道
躁动的绵羊 写道
zhuanggl 写道
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?


     我可不是心血来潮可设这个讨论帖的。在我的项目中,确实出现问题了,经过对堆内存的分析,发现有大量的装载类对象没有被回收,而我的项目中使用了大量的辅助类(里面方法为static的)。
    


这个没有问题,如果不需要用的 方法,可以不写。但是元信息占用内存不大,除非你的项目动态产生了很多字节码。元信息(static方法、字段等)不是放在堆中的,而是放在永久区域,这区域很少被GC。


类和对象一样,在不被使用的时候,也是会被回收的。如果回收了,则这个类对它的类加载器(装载该类的对象)的引用也就没了,从而它的装载类对象就会被垃圾收集。
  现在占堆内存的不是这个类的资源,而是把它加载到方法区的装载类对象,一直不被GC。


lz说到 类和对象一样,在不被使用的时候,也是会被回收的。 能说明什么时候叫作类不被使用。
17 楼 mercyblitz 2011-01-10  
躁动的绵羊 写道
mercyblitz 写道
躁动的绵羊 写道
zhuanggl 写道
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?


     我可不是心血来潮可设这个讨论帖的。在我的项目中,确实出现问题了,经过对堆内存的分析,发现有大量的装载类对象没有被回收,而我的项目中使用了大量的辅助类(里面方法为static的)。
    


这个没有问题,如果不需要用的 方法,可以不写。但是元信息占用内存不大,除非你的项目动态产生了很多字节码。元信息(static方法、字段等)不是放在堆中的,而是放在永久区域,这区域很少被GC。


类和对象一样,在不被使用的时候,也是会被回收的。如果回收了,则这个类对它的类加载器(装载该类的对象)的引用也就没了,从而它的装载类对象就会被垃圾收集。
  现在占堆内存的不是这个类的资源,而是把它加载到方法区的装载类对象,一直不被GC。



那就和你前面说的没有一点关系,关键还是在为什么没有被回收!
16 楼 躁动的绵羊 2011-01-10  
mercyblitz 写道
躁动的绵羊 写道
zhuanggl 写道
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?


     我可不是心血来潮可设这个讨论帖的。在我的项目中,确实出现问题了,经过对堆内存的分析,发现有大量的装载类对象没有被回收,而我的项目中使用了大量的辅助类(里面方法为static的)。
    


这个没有问题,如果不需要用的 方法,可以不写。但是元信息占用内存不大,除非你的项目动态产生了很多字节码。元信息(static方法、字段等)不是放在堆中的,而是放在永久区域,这区域很少被GC。


类和对象一样,在不被使用的时候,也是会被回收的。如果回收了,则这个类对它的类加载器(装载该类的对象)的引用也就没了,从而它的装载类对象就会被垃圾收集。
  现在占堆内存的不是这个类的资源,而是把它加载到方法区的装载类对象,一直不被GC。
15 楼 mercyblitz 2011-01-10  
躁动的绵羊 写道
zhuanggl 写道
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?


     我可不是心血来潮可设这个讨论帖的。在我的项目中,确实出现问题了,经过对堆内存的分析,发现有大量的装载类对象没有被回收,而我的项目中使用了大量的辅助类(里面方法为static的)。
    


这个没有问题,如果不需要用的 方法,可以不写。但是元信息占用内存不大,除非你的项目动态产生了很多字节码。元信息(static方法、字段等)不是放在堆中的,而是放在永久区域,这区域很少被GC。
14 楼 躁动的绵羊 2011-01-10  
zhuanggl 写道
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?


     我可不是心血来潮可设这个讨论帖的。在我的项目中,确实出现问题了,经过对堆内存的分析,发现有大量的装载类对象没有被回收,而我的项目中使用了大量的辅助类(里面方法为static的)。
    
13 楼 yanical 2011-01-10  
请教一下前面的几位高手,类怎么卸载啊?
12 楼 kingkan 2011-01-10  
mercyblitz 写道
对象(实例)永远在Heap上面的,无论是你否是单例。

LZ,误会了,单例模式最多用于那些创建对象开销比较大(时间和空间两个维度),不一定是指内存消耗大。比如:网络延时、文件加载。功能决定了物理空间的大小,而不是方式。

同时,建议LZ应该再深入学习Java数据和元数据。简单地说,编译时需要的属于元数据,比如代码(看得到的方法和字段定义,在Java文件中)。看不到的,在运行时中的数据才是非元数据。

还有类是可以卸载的,肯定是先卸载再回收啊。


+1

单例模式,少new带来的好处是大大滴.
11 楼 mercyblitz 2011-01-10  
对象(实例)永远在Heap上面的,无论是你否是单例。

LZ,误会了,单例模式最多用于那些创建对象开销比较大(时间和空间两个维度),不一定是指内存消耗大。比如:网络延时、文件加载。功能决定了物理空间的大小,而不是方式。

同时,建议LZ应该再深入学习Java数据和元数据。简单地说,编译时需要的属于元数据,比如代码(看得到的方法和字段定义,在Java文件中)。看不到的,在运行时中的数据才是非元数据。

还有类是可以卸载的,肯定是先卸载再回收啊。
10 楼 zhuanggl 2011-01-10  
超级潜水员 写道
蛋疼的忧虑,从没有担心class占内存及回收的,你就算有几亿行代码吧? 能占1G内存么?

不知道有个perm吗?
9 楼 Crusader 2011-01-09  
yanical 写道
躁动的绵羊 写道
sswh 写道
躁动的绵羊 写道
 
    1.如果类中属性或方法是static的,那么在该类被装载到方法区时,是要分配内存的。那如果是static的,是不是表示该类(非对象)永远不会被垃圾收集了呢?从而占用一定的内存空间,如果这样的类多的话,那JVM的可使用内存不是会很少?既然这样,又何必用静态方法呢?(我不太确定含有静态字段或方法的类是否会被垃圾收集器收集


我的理解:

类一旦加载就不会被卸载,这和类是否有静态成员(字段、方法)没关系。
只有类的加载器被回收了,该加载器所加载的类才会被回收。


我可以很负责任的告诉你: 累是可以被卸载的,也可以被缓存的

第二个观点我保留意见。

不知道你说的类怎么卸载? 据我所知确实类加载了就不能卸载,除非加载器被回收。

使用单例、静态的目的就是为了节省JVM内存 ??
没听过这种说法,就算不用单例,同样的代码写在任何地方最终都要被加载,耗掉的内存是一样的,即便那个class被创建了多个instance,它的类的二进制文件也只有一份。所以不存在内存消耗的区别。
当然如果创建多个instance是会有内存占用区别,但是你也说有内存回收了,呵呵。这个就看值不值吧,个人不是那么在意。单例是程序要求,而不是内存性能考虑。

由于Java的安全性特点,加载不同包下的类的加载器一定不会是同一个对象吧。
普通的应用里,除jdk自带类外的其他类是会被同一个加载器加载的。


-------------------------------------------
我想还是存在分别的,类的延迟加载和预先加载的区别,但程序运行稳定时在维持类信息的内存消耗方面应该也是基本稳定的,与类是否单例/静态等无关
静态方法过多应该注意的是对方法堆栈的消耗
另外,servlet就是单例的,怎么能说没用呢?
8 楼 javabkb 2011-01-09  
被回收是肯定的
7 楼 yanical 2011-01-09  
躁动的绵羊 写道
sswh 写道
躁动的绵羊 写道
 
    1.如果类中属性或方法是static的,那么在该类被装载到方法区时,是要分配内存的。那如果是static的,是不是表示该类(非对象)永远不会被垃圾收集了呢?从而占用一定的内存空间,如果这样的类多的话,那JVM的可使用内存不是会很少?既然这样,又何必用静态方法呢?(我不太确定含有静态字段或方法的类是否会被垃圾收集器收集


我的理解:

类一旦加载就不会被卸载,这和类是否有静态成员(字段、方法)没关系。
只有类的加载器被回收了,该加载器所加载的类才会被回收。


我可以很负责任的告诉你: 累是可以被卸载的,也可以被缓存的

第二个观点我保留意见。

不知道你说的类怎么卸载? 据我所知确实类加载了就不能卸载,除非加载器被回收。

使用单例、静态的目的就是为了节省JVM内存 ??
没听过这种说法,就算不用单例,同样的代码写在任何地方最终都要被加载,耗掉的内存是一样的,即便那个class被创建了多个instance,它的类的二进制文件也只有一份。所以不存在内存消耗的区别。
当然如果创建多个instance是会有内存占用区别,但是你也说有内存回收了,呵呵。这个就看值不值吧,个人不是那么在意。单例是程序要求,而不是内存性能考虑。

由于Java的安全性特点,加载不同包下的类的加载器一定不会是同一个对象吧。
普通的应用里,除jdk自带类外的其他类是会被同一个加载器加载的。
6 楼 kevin1988620 2011-01-09  
对于类的内存占用,一向不再考虑的范围内,我在学校折腾java项目时,一向不管三期二十一,把hibernate,spring的jar包不加选择扔到lib下面。与这些jar中的类相比,自己设计的几个辅助类,实在是忽略不计。
而且如果运气不好,碰上out of memery,permgen space的时候,调整一下permsize就可以了。
我觉得内存方面主要要顾及的是往内存的static区域方对象,而不是类

相关推荐

    单例和策略模式示例

    在Java或C#等面向对象的语言中,单例模式通常通过私有构造函数和静态工厂方法来实现。例如,我们可以创建一个名为`Singleton`的类,其构造函数为私有,然后定义一个静态方法`getInstance()`用于返回唯一的实例。这样...

    iOS单例代码

    1. 定义一个接口,声明一个静态实例变量和一个类方法来获取该实例。 ```objc @interface Singleton : NSObject + (instancetype)sharedInstance; @end ``` 2. 在实现文件中,我们使用`@synchronized`关键字确保...

    三种工厂设计模式和两种单例模式

    在本文中,我们将深入探讨三种工厂设计模式——简单工厂模式、抽象工厂模式和工厂方法模式,以及两种单例模式——饿汉单例模式和懒汉单例模式。这些模式都是面向对象设计中的重要组成部分,对于理解和构建可维护、可...

    c++单例模式线程日志类

    在这个特定的场景中,我们讨论的是一个实现了单例模式的日志类,该类专为多线程环境设计,具备日志等级控制、精确的时间戳以及可变长参数和标准格式化输出的功能。 首先,让我们深入了解单例模式。单例模式的主要...

    wpf 单例模式和异常处理

    首先,让我们深入理解单例模式。在C#中,我们可以使用静态成员或双重检查锁定(Double-Check Locking)来实现单例。静态成员方法是最简单的实现方式,但可能会在多线程环境下引发问题。因此,更安全的方法是使用双重...

    基于Qt的日志单例。

    本文将深入探讨基于Qt的日志单例的设计与实现。 首先,让我们理解什么是单例模式。单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。这样可以避免资源浪费,特别是对于日志系统这种在整个...

    c++静态成员使用实例

    本篇将通过两个实例——静态成员函数和静态数据成员,深入探讨它们在C++中的应用。 首先,我们来看静态成员函数。在C++中,静态成员函数可以被类的所有对象共享,它并不持有隐含的`this`指针,因此不能访问非静态...

    游戏角色创建程序(单例模式)

    2. 单例类(CharacterSingleton):持有角色类的单例实例,提供静态方法供外部获取角色创建服务。 3. 初始化逻辑:在单例类中处理角色的初始化,如读取默认设置或从数据库加载信息。 4. 线程安全措施:如使用...

    Android-toast的基本封装包括单例化成功和失败的提示吐司

    本篇文章将深入探讨如何对`Toast`进行基本封装,特别是实现单例化以及针对成功和失败场景的定制化提示。 首先,让我们理解`Toast`的基本用法。`Toast`类在`android.widget`包中,通过`makeText()`方法创建一个`...

    Java编程子类能否重写父类的静态方法探索

    Java 编程中,子类能否重写父类的静态方法是一个值得讨论的问题。通过实例探索,我们可以了解到父类的静态方法可以被子类继承,但是不能重写。 首先,我们来看一下父类的代码: ```java public class Fu { public ...

    Swift 实现单例 代理 通知 的设计模式 OC 跟 Swift 如何混编

    本篇文章将深入探讨如何在Swift中实现单例、代理和通知这三种常用的设计模式,并讲解如何在Swift与OC之间进行有效的混编,包括创建按钮和实现页面跳转。 首先,我们来看Swift中的单例设计模式。单例是一种确保类...

    C++静态成员、友元函数、类模板实验

    通过这些实验,学习者可以深入理解静态成员如何在类实例间共享数据,友元如何突破封装界限进行有效协作,以及类模板如何提高代码的重用性和灵活性。同时,实验还能帮助学习者巩固面向对象编程的基本原则,提升其编程...

    Java内存泄露及内存无法回收解决方案

    其中,堆内存是Java对象的主要存储场所,栈内存主要存储方法调用时的局部变量,而方法区则存储类的信息,如类的常量池、字段和方法数据等。 内存泄漏通常发生在堆内存中,当程序创建对象并分配内存后,如果不再需要...

    毕向东静态07

    总之,"毕向东静态07"的Java基础教程深入浅出地讲解了面向对象设计中的重要一环——单例设计模式,特别是通过双重检查锁定实现的懒汉式单例,对于初学者和有一定经验的开发者来说,都是提升技能的重要学习材料。

    WPF应用中的实数单例方法

    文件"Real-Singleton-Approach-in-WPF-Application.pdf"可能包含了更深入的讨论,包括线程安全的单例实现(如双重检查锁定或使用`Lazy<T>`类型),以及在WPF环境中单例模式的特定应用场景和最佳实践。"下载链接.txt...

    关于Java方面的面试题目

    Java是世界上最流行的编程...以上只是Java面试中可能涉及的部分知识点,实际面试中可能会根据职位需求和技术栈深度进行更深入的讨论。通过准备这些知识点,候选人可以更好地应对Java相关的面试挑战,提升自己的竞争力。

    静态成员与友元实验报告共7页.pdf.zip

    实验报告的七页内容可能详细阐述了这些概念,通过实例代码和结果分析,帮助学习者深入理解静态成员和友元的作用,并掌握如何在实际编程中合理利用它们。遗憾的是,由于无法直接查看压缩包内的具体文件,我们无法提供...

    单例模式七种写法_转

    在讨论双重检查锁定失效的原因之前,让我们先从单例模式的基本实现开始,逐步深入。最简单的单例模式实现方式是将构造函数设为私有,并在类内创建一个静态的类实例,同时提供一个公共的静态方法来获取这个实例。这种...

    静态

    静态变量和静态方法在类的所有实例之间共享,它们不会随着实例的创建而复制。在TypeScript中,我们可以使用`static`关键字来声明静态成员。 1. 静态变量: 类中的静态变量可以在没有创建实例的情况下被访问。它们...

    研磨设计模式--chjavach的博客文章

    在Java中,通常通过私有构造器和静态工厂方法来实现单例,同时要防止反射和序列化破坏单例的唯一性。 其次,是**工厂方法模式**。它是一种创建型设计模式,提供了一种封装对象创建过程的方法,使得创建过程可以延迟...

Global site tag (gtag.js) - Google Analytics