这是我的用例.我们正在尝试缩小应用程序中潜在的内存泄漏,我们正在使用内存分析工具对堆进行快照,以便我们可以查找对象实例和引用.(如果它有帮助,我们正在使用YourKit.)
该应用程序广泛使用动态和CGLIB代理,最终在WeakHashMaps中存储大量类和类加载器的引用.
在我们的测试用例运行之后,我们期望对对象X及其类加载器的所有硬引用都消失了,但是由于测试用例中涉及很多代理,我们还有许多弱/软引用.(我只能找到WeakHashMap引用,但是YourKit将弱引用和软引用都包含在摘要中的一个行项中,所以我不能确定我在某处没有错过软引用.)
即使在从JVM请求完整GC之后也是如此.(在服务器模式下使用sun 1.6.0_23 JDK.)
这看起来好像JVM承认有这些对象只弱/软引用,但我不能强迫它GC这些东西是100%肯定.(所以,我想要的是,它完全从堆中消失,其permgen的类加载器使用也会消失.)
任何人都知道配置和/或强制JVM处理仅软/弱引用的对象的方法吗?
java garbage-collection reference weak-references soft-references
我有一个与谷歌存储和谷歌日志记录集成的 python 3.7 谷歌云函数,因此我使用该函数部署了一个密钥文件,并使用 GOOGLE_APPLICATION_CREDENTIALS 环境变量引用它。一切都工作正常,因为我的函数执行了它应该做的事情并返回正确的输出等,唯一需要注意的是它正在将错误级别的内容记录到看起来应该是 INFO 或更低的级别。或者...也许我错过了一些东西,但我不想在这里错过一些东西。
底线:我想要干净的日志,以便错误/警告有意义,并且我不必处理噪音。
您会注意到,我自己的日志记录显示在“调试”级别,但在它之前和之后是看似无害的日志条目,被标记为“错误”。(是的,我知道我自己的日志条目出现了 2 次,一次在调试时,一次在信息处 - 这是另一个问题,但对我来说优先级较低。)
这对于谷歌云功能来说是正常现象吗?或者我可以做些什么来纠正这个问题?
更新:
以下是我在 python 代码中配置日志记录的方法:
import logging
import logging.config
import google.cloud.logging
client = google.cloud.logging.Client()
client.get_default_handler()
client.setup_logging()
logging.getLogger().setLevel(logging.DEBUG)
Run Code Online (Sandbox Code Playgroud)
现在,我注意到在本地调试(使用函数框架)中,我也将这些相同的消息输出到控制台,而没有任何日志条目元数据,因此通过谷歌客户端代码进行跟踪,我注意到客户端代码只是使用python 日志库,当它们在调试时输出这些消息时,它们以某种方式绕过了我期望在这里使用的 google 日志钩子。因此它们被输出到 stderr,当然谷歌的日志记录将其解释为错误。
这并没有回答我自己的问题,而是添加了更多上下文,希望其他人已经解决了这个问题。
更新 #2 - 一个丑陋的解决方案,需要一个更好的解决方案
在对谷歌云客户端代码进行了更多挖掘之后,我得到了答案,尽管我不喜欢它,也不喜欢我正在做的“修复”这个问题。
发生的事情是,当该函数在 GCP 中部署并运行时,Python 日志记录框架会以某种方式使用其他处理程序进行初始化。调用 client.setup_logging() 后,如果我打印出附加到根记录器的处理程序,我会看到:
root handlers=[<StreamHandler (NOTSET)>, <StreamHandler (WARNING)>, <CloudLoggingHandler (NOTSET)>]
Run Code Online (Sandbox Code Playgroud)
接下来,为了让事情变得更有趣,当调用 setup_logging() 时,有一些“排除的记录器”硬编码到客户端代码中,以将它们排除在使用 CloudLoggingHandler 之外(有一条注释指出,如果不这样做,我们就会请参阅无限递归)。因此,使用这些特定于 google 的记录器记录的任何内容都将始终转到我上面捕获的 StreamHandler 之一或两个。
AND,最后的解释:StreamHandler 使用的默认流是 stderr,谷歌的日志报告正确地(恕我直言)将其解释为“错误”。
因此,有了这个解释,我至少可以在我自己的函数类中使用以下代码来解决这个问题:
import logging
import google.cloud.logging
client = google.cloud.logging.Client()
client.setup_logging() # NOTE specifying …Run Code Online (Sandbox Code Playgroud) 我一直在我们的应用程序中处理类加载器泄漏,最终达到了对CL的所有引用都消失的程度.在我的内存分析工具(使用YourKit和jmap/jhat)中,我可以强制GC有时会立即摆脱我的类加载器,但其他时候(取决于应用程序使用情况,但这是我可以得到的具体)当我强制GC,CL实例不会消失.我捕获一个内存快照并查看结果,它说该对象存在,但无法访问.
这是古怪的部分......我只是偶然发现了这一点.
我可以强制使用我想要的全部GC,但实例并没有消失.然而,在10-20分钟之后,如果我再做一次完整的GC,它确实会被收集.
(在此期间,申请大部分是不活动的(并非完全).我的"延长"咖啡休息时间是导致这一发现的事故.)
所以我对这里泄漏的担忧已经消失(希望如此),但问题现在更多是试图解释这种行为.
任何人都知道什么可能导致太阳JVM决定不收集无法访问的类加载器20分钟?
Sun JVM版本详细信息:
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) 64-Bit Server VM (build 19.0-b09, mixed mode)
Run Code Online (Sandbox Code Playgroud) 我们目前使用MyEclipse与其内置的Maven4MyEclipse集成及其内置的J2EE服务器支持,但希望转换为常规eclipse(特别是Helios)以便能够在Windows上使用其64位安装.(MyEclipse在Windows上还不支持64位.)
到目前为止,我已经有了一个Helios eclipse的工作原型,使用m2eclipse和WTP插件将我们的大型Web应用程序部署到tomcat.部署有点处理器,但它可以工作,应用程序启动.
这里严重不同的是如何部署依赖项目.在我们的MyEclipse环境中,所有依赖项目都被部署到WEB-INF/classes文件夹中,因此在服务器运行时,对IDE中的java类的更改只会将受影响的文件复制到服务器的WEB-INF /类和热交换类到JVM和...繁荣 - 实时更改到服务器.非常适合调试.
然而,在我的helios转换中,所有依赖项目都获得JAR并放入WEB-INF/lib.这实际上看起来像我们真正的maven制造的生产图像看起来像,但开发环境因此严重不利,因为热交换功能似乎完全丢失了.在这里,如果我在依赖项目中更改java类,m2eclipse将重新打包JAR,看到部署的Web应用程序不同步,并重新发布整个应用程序.这不仅是一个问题,因为整个Web应用程序必须循环(鉴于它的大小和巨大的初始化时间,我们坦率地说它们做得不好),这也是eclipse在重新发布时的一个令人讨厌的延迟.(对于我们的应用程序,这需要大约一两分钟.)
所以我的问题是这样的:有没有办法让依赖项目内的更改热插拔到正在运行的JVM并替换已部署的文件而没有这种令人讨厌的重新发布惩罚?我假设这意味着将这些类文件部署到WEB-INF/classes,但不确定(a)是否可能或(b)作为此解决方案的一部分真正必要.
其他人在做什么来解决这个问题?它可以解决吗?
提前致谢!
我们一直在推动我们应用程序中的permgen内存空间越来越高,我试图找出我们是否有某种类型的泄漏进入permgen区域.我们不做热取消部署/重新部署操作,但我们有很多代理,包括动态和CGLIB生成.我们还做了一些复杂的类加载器位来支持各种用例,我怀疑这些也可能是导致permgen浪费的一个原因.
所以我在运行的应用程序上运行jmap -permstat,希望能够深入了解可能填补我们permgen空间的内容.(我还运行带有实时和死对象的正常堆转储,这样我就可以追溯可能来自permstat输出的线索).
但是,在jmap permstat列出的2400个类加载器中,除引导类加载器之外的所有类都被列为"死".这没有任何意义,因为该应用程序绝对是直播和工作.
我的理解是,如果有资格进行垃圾收集,jmap会将类加载器报告为"死"但我在这里肯定是错的......
我错过了什么?"死"在这里意味着什么?除了我在这里可能存在的误解之外,谷歌搜索并没有提供很多答案.
我正在第一次尝试 GCP 的云函数和 python,并希望将 python 的日志记录充分集成,以便它们能够很好地适应 GCP 的日志记录基础设施(特别是为了识别严重性级别,并且最好还包括execution_ids 和跟踪 id)。
我一直在关注https://cloud.google.com/logging/docs/setup/python来进行此设置。
我的代码:
import base64
import logging
import google.cloud.logging
client = google.cloud.logging.Client()
client.get_default_handler()
client.setup_logging()
logging.getLogger().setLevel(logging.DEBUG)
def sample_pubsub(event, context):
pubsub_message = base64.b64decode(event['data']).decode('utf-8')
print('BEFORE LOG')
logging.info(f'Event received: payload data == [{pubsub_message}]')
logging.debug('This is debug')
logging.warn('This should be a warning')
logging.error('This should be an error')
print('AFTER LOG')
Run Code Online (Sandbox Code Playgroud)
当我使用函数框架在本地运行它时,它完美地工作(据我所知),像这样输出到控制台:
{"message": " * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)", "timestamp": {"seconds": 1609443581, "nanos": 119384527}, "thread": 140519851886400, "severity": "INFO"}
{"message": " * Restarting with …Run Code Online (Sandbox Code Playgroud) java ×3
classloader ×1
eclipse ×1
eclipse-wtp ×1
jmap ×1
jvm ×1
logging ×1
m2eclipse ×1
maven-2 ×1
memory ×1
multi-module ×1
permgen ×1
profiling ×1
python ×1
reference ×1