我们有很多类代码,它们有一些如下所示的样板:
private static Logger logger = null; private static Logger getLogger() { if (logger == null) { logger = Logger.getLogger(MyClass.class); } return logger; }
这个想法是类可以将调试内容记录到Logger中.需要记录某些内容的第一个代码调用getLogger()并使记录器存在.
关于这种模式,有几件我不喜欢的事情.首先,单例getLogger()不同步并同步它,而正确会无缘无故地给每个后续调用带来负担.
我真的希望能够将其压缩到这样:
private static final Logger logger = Logger.getLogger(MyClass.class);
然后我可以直接引用记录器,甚至不用单独的getter.
我担心的问题是,通过这样做,即使从未调用过记录器,我也会在加载类时创建一个Logger.我有10,000个奇怪的类都调用了getLogger(),所以我实际上在这里创建了多少个Logger实例?如果我的log4j属性包含一些appender,我只是一遍又一遍地引用相同的记录器,或者我是在创建10,000个这样的东西?
解决方法
如果使用默认的Log4j配置(即默认的LoggerRepository,DefaultCategoryFactory等),那么您将创建10’000个Logger实例.他们消耗了多少内存?除了上帝和你的探查器之外没有人知道这一点. (我的猜测只有后一个会告诉你).
如果内存占用对于您的环境来说太多,请将Logger初始化移动到静态内部类,如下所示:
static class LoggerHolder { static Logger logger = Logger.getLogger(MyClass.class); } private static Logger getLogger() { return LoggerHolder.logger; }
这样,Logger的实例将仅在第一次getLogger调用时创建. (这种技术称为初始化按需持有者(IODH),它是线程安全的,并且没有同步开销).
我可以给你一个offtopic建议吗?考虑将Log4J替换为SLF4J Logback库的组合.它们是由同一个作者编写的,并描述为“流行的log4j项目的继承者,在log4j离开的地方”.您可以在this SO thread阅读更多内容.