本篇文章给大家谈谈java–这是资源泄漏还是误报?,以及java资源泄露怎么处理的知识点,同时本文还将给你拓展191206_01Java中的句柄与资源泄露、android-如何检查属性是维度,整数还是
本篇文章给大家谈谈java – 这是资源泄漏还是误报?,以及java资源泄露怎么处理的知识点,同时本文还将给你拓展191206_01 Java中的句柄与资源泄露、android-如何检查属性是维度,整数还是资源ID、Android:在附加的堆栈跟踪中获取资源但从未发布.有关避免资源泄漏的信息,请参阅java.io.Closeable、C ++ Winsock接受内存泄漏/资源泄漏等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- java – 这是资源泄漏还是误报?(java资源泄露怎么处理)
- 191206_01 Java中的句柄与资源泄露
- android-如何检查属性是维度,整数还是资源ID
- Android:在附加的堆栈跟踪中获取资源但从未发布.有关避免资源泄漏的信息,请参阅java.io.Closeable
- C ++ Winsock接受内存泄漏/资源泄漏
java – 这是资源泄漏还是误报?(java资源泄露怎么处理)
Random r = new Random(); try(PrintWriter out1 = new PrintWriter("one.txt"); PrintWriter out2 = new PrintWriter("two.txt")) { PrintWriter out = r.nextBoolean()?out1:out2; out.println("x"); }
P.S.:警告是“资源泄漏:’out’永远不会关闭”.
解决方法
我很久以前就关闭了Eclipse中那些与资源相关的警告.它们真的不可靠,因为有很多“明显”正确的控制流路径,Eclipse无法在没有实际执行的情况下将其识别为“正确”……任何非平凡的代码都注定会产生这些误报.
191206_01 Java中的句柄与资源泄露
Java中的句柄与资源泄露
本文内容介绍Java中的句柄与资源泄露问题,是Java网站开发中必须清楚掌握的基本概念。句柄包括两类:文件句柄和网络句柄。本文是Java学习指南系列教程的官方配套文档,配套示例代码或者视频讲解。
在项目开发中,句柄的概念极为重要。如果不了解句柄,就可能发生以下错误:
- 文件被占用,无法删除或移动
-Tomcat资源占满,无法访问
-MySQL数据库连接数已满,无法连接
1. 文件句柄
句柄 ( Handle ) ,是一种系统资源。在实际编程中分为两类:文件句柄,网络句柄(Socket)。
先说文件句柄。当在程序里打开一个文件的时候,操作系统内核里创建了一个文件句柄,该句柄为当前进程拥有。比如,
InputStream inputStream = new FileInputStream(“C:\test\example.txt”);
此时就打开了一个文件句柄。文件句柄在用完之后一定要执行close 关闭,在close的时候会释放系统资源。即使用以下的代码框架:
InputStream inputStream = new FileInputSteam( file );
try{
... 读取文件 ...
}
finally{
inputStream.close();
}
无论在try{}中有无异常发生,总是在finally{}中执行close()方法,确保文件句柄的释放。
涉及到文件句柄的地方有:
// 读取一个文件
InputStream inputStream = new FileInputStream( file )
// 写入一个文件
OutputStream outputStream = new OutputStream (file)
// 随机读写文件 ( 不常见 )
RandomAccessFile raf = new RandomAccessFile (file, "rw")
也就是说,创建一个InputStream / OutputStream / RandomAccessFile 对象时,各自对应了一个句柄。所有带句柄的对象,在用完之后要记得关闭掉。
需要区分的是,File对象只是一个文件路径,相当于String的包装类,它是不对应文件句柄的。例如,File f = new File(“C:\test\example.txt”) 这只是定义了一个路径,什么事都没有发生,不会创建文件句柄。
2. 网络句柄
当在项目中使用网络编程技术时,也需引起我们的注意。一个Socket对应一个句柄,可以称为网络句柄。网络句柄和文件句柄一样,都是有限的资源,也是用完了就必须关闭。
涉及网络句柄的地方有:
2.1 Socket 和 ServerSocket
在TCP网络编程中的Socket和ServerSocket代表了网络句柄,以下示例详见Java学习指南系列的《网络通信篇》视频教程。
// 服务器:创建一个ServerSocket的时候,句柄数加1
ServerSocket serverSock = new ServerSocket(2019);
// 服务器:接收到一个客户端连接的时候,句柄数加1
Socket sock = serverSock.accept();
// 客户端:连接上服务器的时候,句柄数加1
Socket sock = new Socket();
sock.connect( new InetSocketAddress("127.0.0.1",2019));
也就是说,一个Socket / ServerSocket 对象各自对应了一个句柄。
2.2 JDBC Connection
在数据库JDBC编程中,需要获取一个Connection对象,代表一个与MySQL服务器之间的一个链接。例如,
Connection conn = DriverManager.getConnection(connectionUrl, username, password);
try{
...
} finally {
conn.close();
}
这个Connection对象内部会包含一个Socket连接,所以它也对应一个句柄,在用完后应当及时关闭。
2.3 HttpServletRequest和HttpServletResponse
在Java网站开发时,HttpServletRequest和HttpServletResponse内部包含了网络Socket连接,但是这个Socket是被Tomcat框架自己管理的,我们看不到也管不着。
比如,在处理Servlet请求时,
OutputStream outputStream = response.getOutputStream();
outputStream.write( data );
可以脑补一下,从HttpServletResponse获取OutputStream,其内部实现不就是从Socket中获取OutputStream吗?
Tomcat本身是一个Java写的TCP服务器,当一个客户端请求到来时,它会创建一个Socket并创建一个线程来处理。所以在实际运行时,一个请求对应一个线程和一个Socket资源的。再强调一遍,这个Socket是由Tomcat自行管理的,我们看不到也管不着。
3. 句柄数量的监测
一个进程可创建的句柄是有限的,以前的Windows或Linux上最多可以创建约2000多个。但是最新的Win10系统似乎突破了这个限制。
可以自己试一下,
public static void main(String[] args) throws Exception
{
File file = new File("C:/test/example.txt");
byte[] buf = new byte[4000];
for(int i=1; i<10000; i++)
{
InputStream is = new FileInputStream(file);
is.read(buf);
System.out.println("创建第" + i + "个文件句柄");
}
System.out.println("Exit.");
}
在任务管理器里,可以观察到一个进程所占用的系统资源,如CPU、内存、线程数、句柄数。其中,线程和句柄两列默认是隐藏的,必须打开这两列的显示。按 CTRL + SHIFT + ESC,打开任务管理器,如下图所示。
如果没有显示句柄这一列的话,可以右键点一下CPU这个标签,选择列即可显示(自己百度一下)。
在这里可以看到每一个进程所占用的资源情况,我们的Java进程的名称是java.exe或者javaw.exe。比如,Eclipse启动时对应一个javaw.exe进程。
以单步调试的方式运行上述代码,可以发现每创建一个FileInputStream对象,该进程的句柄数会加1。如果调用了close()方法,则句柄数会减1。
4. 句柄与GC垃圾回收
Java里有一个GC垃圾回收机制,可以把失去引用的对象自动回收。比如,
for(int i=1; i<10000; i++)
{
InputStream inputStream = new FileInputStream(file);
inputStream.read(buf);
System.out.println("创建第" + i + "个文件句柄");
}
此处,每一轮循环创建一个对象inputStream,此对象在循环之后失去引用,会被自动回收(销毁)。但是需要区分的是,此处销毁的是对象自身,并没有释放句柄啊!
在Java里,一定要显式地调用inputStream.close()才能够释放这个inputStream所对应的句柄资源。句柄释放和GC机制是两码事!
5. try-with-resources
在有的代码里,形式上看不到close()的调用,但是句柄在内部被关闭了。比如,在MyBatis编程中经常可见的代码:
try ( SqlSession session = sqlSessionFactory.openSession() ) {
// do work
}
在这里,并没有看到 session.close() 的调用,为什么呢?
此种try语法称为 try-with-resources,在小括号里是一个称为资源的对象。资源对象类型,就是实现了java.lang. AutoCloseable接口的类型。语法规定,在try{} 运行完后会自动调用resource.close()方法来关闭资源。可以认为这种语法是对try { } finally{} 的简写,相当于:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
}
finally {
session.close();
}
记住,此种try-with-resources语法,是要求资源对象类型是实现了AutoCloseable接口的。你得自己检查一下,有这个接口的类型才能这么简写。
6. 线程与句柄
线程数和句柄数,都是有限的资源。一个程序不能开太多的线程,也不能开太多的句柄。
在网站开发中,这两个概念是相关的。表现在:
(1) 当一个请求到来时,Tomcat创建一个线程,在线程里处理这个请求Socket。所以一个请求对应了一个线程和一个Socket句柄。
(2) 无论是线程占满、还是句柄占满,都会导致系统不可访问。
比如,如果句柄占满,则Tomcat无法创建新的Socket连接,自然也就不能访问了。
7. 句柄与服务器的稳定性
在网站开发中,通过观察任务管理器中的句柄数,可以检查有没有句柄泄露的情况。
如果句柄数保持稳定,则没有问题。如果持续增加、不见减少,就说明你的程序代码里有句柄泄露。如果已经达到上限(2000-3000),则服务器已经不可访问。
所谓句柄泄露,就是说你打开一个句柄但是忘了close掉。比如,
- 打开了一个FileInputStream / FileOutputStream / RandomAccessFile 对象
- 打开了一个数据库连接 Connection 对象 ( 或者封装后的 SqlSession 等)
- 打开了一个Socket连接对象
- 使用HttpClient / FTP Client等封装后的API,打开了一个网络连接但没有close掉 ...
凡是涉及到这些调用的地方,一定要仔细核对,因为这关系到你的服务器是否能长期稳定地运行。
最后,本文演示所用的项目源码及视频讲解 在此处获取 ,更多教程请注意 阿发你好 的Java学习指南系列教程。
android-如何检查属性是维度,整数还是资源ID
我试图创建一个相对简单的自定义视图,在该视图中,根据代码的位置,XML描述一个离散值(“ 100dp”)或资源值(“ @ dimen / standardWidth”).
我不确定如何检查返回的值是否为resid,整数或维值(因为getDimenion(),getInt()和getResourceID()都返回看起来相同的值).
我使用以下代码:
<declare-styleable name="LabeledView">
...
<attr name="labelWidth" format="dimension|reference"/>
...
</declare-styleable>
在我的自定义视图中,我使用以下代码:
if (attrs!=null) {
TypedArray typedArray = getContext().obtainStyledAttributes(
attrs, R.styleable.LabeledView, 0, 0);
int labelWidth = typedArray.getResourceId(R.styleable.LabeledView_labelWidth, -1);
在上面的示例中,labelWidth等于2131165193,因为它实际上是@dimen的残差.
解决方法:
仅使用尺寸格式,不提供参考.但是,您可以为属性使用参考值.应将其视为实际尺寸.
<attr name="labelWidth" format="dimension"/>
typedArray.getDimensionPixelSize
Android:在附加的堆栈跟踪中获取资源但从未发布.有关避免资源泄漏的信息,请参阅java.io.Closeable
当我运行我的Android应用程序时,我收到以下错误:
10-12 16:46:44.719 2710-2719/? E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
10-12 16:46:44.719 2710-2719/? E/StrictMode: java.lang.Throwable: Explicit termination method 'end' not called
10-12 16:46:44.719 2710-2719/? E/StrictMode: at dalvik.system.CloseGuard.open(CloseGuard.java:184)
10-12 16:46:44.719 2710-2719/? E/StrictMode: at java.util.zip.Inflater.
这个错误意味着什么,我该如何解决?
最佳答案
你能分享你的代码吗?您是否使用模拟器来运行应用程序或物理设备?
因为可能有很多原因:
>你已经打开了一些东西但从未关闭它们. Closable有一个close()方法,当你不再需要它时,你必须调用它来手动释放与组件相关的打开资源(例如在finally块中).
>此外,当AndroidManifest.xml中存在问题时,会显示该错误消息.例如,当< activity>标签意外地退出< application>
>默认情况下,仿真器启用StrictMode,在实际设备上,可以通过以下代码打开代码:
码:
StrictMode.setVmPolicy (new StrictMode.VmPolicy.Builder().detectAll().penaltyLog()
.penaltyDeath().build());
C ++ Winsock接受内存泄漏/资源泄漏
我已经写了一个小testingTCP侦听器。 所述监听器监听端口28328并且工作得非常好,期望每当客户机连接到它时发生巨大的资源/内存泄漏。
#include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") SOCKET Socket = INVALID_SOCKET; bool TestServer() { WSADATA wsaData = { 0 }; if (WSAStartup(MAKEWORD(2,2),&wsaData)) return false; sockaddr_in addr = { 0 }; Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); int Enable = 1; setsockopt(Socket,SOL_SOCKET,SO_REUSEADDR,(const char*)&Enable,sizeof(int)); addr.sin_family = AF_INET; addr.sin_port = htons(28328); addr.sin_addr.s_addr = INADDR_ANY; if (bind(Socket,(sockaddr*)&addr,sizeof(sockaddr))) return false; if (listen(Socket,50)) return false; return true; } void Dolisten() { if (TestServer()) { sockaddr_in addr = { 0 }; SOCKET Client_Socket = 0; int Lenght = sizeof(addr); for (;;) { Client_Socket = INVALID_SOCKET; Client_Socket = accept(Socket,(struct sockaddr *)&addr,&Lenght); if (Client_Socket == INVALID_SOCKET) continue; printf("Client Connected %Xn",Client_Socket); shutdown(Client_Socket,2); closesocket(Client_Socket); } } } int main(int argc,char* argv[]) { Dolisten(); WSACleanup(); return 0; }
虽然原来的听众比这个大得多,可能还有更多的问题,我还没有得到,现在这是我最大的问题。
我认为这个问题是由于接受了套接字而发生的,它不能正确closures,然后泄漏到一个句柄泄漏处。 我基于这样的事实,当我看着任务pipe理器和其他监视进程的工具时,我可以看到处理计数与我的连接发生的速度相同。
注意:
工具来确定内存泄漏在AC / C + +代码
如何查看vmmap中的更改?
Python脚本不能正确重启
在Linux上debugging内存泄漏
使用MapViewOfFile,指针最终走出内存空间
1)通过它的外观,泄漏发生在非分页存储器上。
2)如果在Linux环境中编译和使用这段代码,将不会产生相同的内存/资源泄漏。
3)我已经在多个Windows机器上编译和testing了这个代码,并且出现了同样的问题。
4)(编辑)我曾经在一些MSDN论坛和VS论坛上看到过几个有这个问题的人,但是他们被告知要做的就是提交一张票。
如果/何时取消分配的堆内存得到回收?
检查正在运行的程序中的内存泄漏
我用过的记忆去了哪里?
屏蔽图书馆泄漏的应用程序
有没有更好的客户端查看系统监视器日志?
您所显示的应用程序中没有内存泄漏。
由于TCP / IP的工作方式,与关闭连接相关的资源不能立即释放。 数据包可能无法到达,或在连接关闭后重新传输。 所以,即使在调用closesocket ,实际的OS套接字仍然保持打开一段预定义的时间(通常2-3分钟,可以用TcpTimedWaitDelay调整)。
如果你运行netstat -an ,你会在CLOSE_WAIT或TIME_WAIT状态看到一堆连接:
TCP 127.0.0.1:28328 127.0.0.1:56508 TIME_WAIT TCP 127.0.0.1:28328 127.0.0.1:56510 TIME_WAIT TCP 127.0.0.1:28328 127.0.0.1:56512 TIME_WAIT TCP 127.0.0.1:28328 127.0.0.1:56514 TIME_WAIT TCP 127.0.0.1:28328 127.0.0.1:56516 TIME_WAIT . . .
当然,(内核)内存需要存储这些临时状态。
此外,临时范围内的TCP端口号不能立即重新使用,这意味着您可以打开/关闭连接的速率非常有限。
非分页池是内核资源,涉及操作系统无法分页的内存,是一种稀缺资源。 所以留意一下,是件好事。
它在内核中的事实意味着内存不是直接在你的控制之下。 内存可能与未发送,未处理的数据包有关,这种情况下,资源是间接负责你的程序的。
检查手柄是否泄漏 – 是从哪里来的。 应用程序验证程序Microsoft:应用程序验证程序下载可以帮助识别正在泄漏内存和句柄的调用栈。
关于java – 这是资源泄漏还是误报?和java资源泄露怎么处理的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于191206_01 Java中的句柄与资源泄露、android-如何检查属性是维度,整数还是资源ID、Android:在附加的堆栈跟踪中获取资源但从未发布.有关避免资源泄漏的信息,请参阅java.io.Closeable、C ++ Winsock接受内存泄漏/资源泄漏的相关信息,请在本站寻找。
本文标签: