T
timjowers
URLConnection leaks memory and after a while will return the memory. No
amount of calling System.gc(); will clean it up. OK for small apps but
I am writing one that downloads 100 or so pages synchronously. OK
unless I experience several clients asking my server to do this at
once. Then Java gives the almost useless OutOfMemoryError. So much for
Garbage Collection. At this point GC just means random
non-deterministic memory management and means, unlike in C++, I cannot
achieve a robust server application. How can Java justify giving
OutOfMemoryError when NO REFERENCES ARE HELD IN MY PROGRAM!!!! I guess
URLConnection must have some internal static buggy code.
Any ideas how to get URLConnection to stop hanging onto memory?
Here's some test code below.
TimJowers
/**
* Sample memory
*/
import java.net.*;
import java.io.*;
import java.util.*;
import java.security.*;
public class Leaky {
public String strXML = null;
private String proxyHost=null, proxyPort=null, username=null,
password=null,
httpRequest=null, base64Encoded=null, proxyType="2",
formValues=null, formMethod="", optionFile=null;
private URL url=null;
private URLConnection urlConnection=null;
private InputStream is=null;
private File file=null;
private FileOutputStream out=null;
private int ftpPort=21;
private boolean notAssigned = true,
ftpTrue=false, ftpPassive=false, ftpAscii=false,
https=false, nonverbose=true, post=false, booleanOptionFile=false;
private StringBuffer sbuf = null;
private byte[] bytesRead = new byte[4096];
protected void zeroMem()
{
strXML = null;
proxyHost=null; proxyPort=null; username=null; password=null;
httpRequest=null; base64Encoded=null;
formValues=null;
formMethod=""; optionFile=null;
url=null;
urlConnection=null;
is=null;
file=null;
out=null;
sbuf = null;
bytesRead = null;
}
public URLConnection setupProxy ( String [] args ) throws Exception
{
getOptions(args);
if (https) {
if (!nonverbose) {
System.out.println("Using https communication");
}
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("http.keepAlive", "false");
System.setProperty( "java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol" );
}
if (formMethod != null && formMethod.equalsIgnoreCase("get")) {
httpRequest = httpRequest + "?" + encodeHttpString(formValues);
}
try {
url = new URL(httpRequest);
} catch (MalformedURLException e) {
if (!nonverbose) {
System.err.println("Malformed URL, must be
http://somehost[/file]");
} else {
throw new Exception("Malformed URL, must be
http://somehost[/file]");
}
return null;
}
if (proxyHost != null) {
if (proxyType.equals("1") || proxyType.equals("3")) {
System.getProperties().put( "proxySet", "true" );
System.getProperties().put( "proxyHost", proxyHost);
System.getProperties().put( "proxyPort", proxyPort);
} else {
if (proxyType.equals("4")) {
System.getProperties().put( "socksProxySet", "true");
System.getProperties().put( "socksProxyHost", proxyHost);
System.getProperties().put( "SocksProxyPort" , proxyPort);
} else {
if (proxyType.equals("5")) {
System.getProperties().put( "ftpProxySet", "true" );
System.getProperties().put( "ftpProxyHost", proxyHost );
System.getProperties().put( "ftpProxyPort", proxyPort );
} else {
System.getProperties().put("firewallSet", "true");
System.getProperties().put("firewallHost", proxyHost);
System.getProperties().put("firewallPort", proxyPort);
System.getProperties().put("http.proxyHost", proxyHost);
System.getProperties().put("http.proxyPort", proxyPort);
}}}
if (https && proxyHost != null) {
System.getProperties().put("https.proxyHost", proxyHost);
System.getProperties().put("https.proxyPort", proxyPort);
}
}
try {
urlConnection = url.openConnection();
} catch (IOException e) {
if (!nonverbose) {
System.err.println("Error opening URL connection to " +
httpRequest);
} else {
throw new Exception("Error opening URL Connection to " +
httpRequest);
}
return null;
}
if (proxyHost != null) {
Base64 base64 = new Base64(username + ":" + password);
base64.encode();
base64Encoded = "Basic " + base64.getOutgoing();
urlConnection.setRequestProperty("Proxy-Connection","Keep-Alive");
if (proxyType.equals("3")) {
urlConnection.setRequestProperty("Authorization",
base64Encoded);
} else {
urlConnection.setRequestProperty("Proxy-Authorization",
base64Encoded);
}
}
return urlConnection;
}
public boolean doWget ( String args ) throws Exception {
// if args are all on one string then break into an array of strings
StringTokenizer strTok = new StringTokenizer( args );
String []argv = new String[ strTok.countTokens() ];
for(int i=0; strTok.hasMoreTokens(); i++ )
argv = strTok.nextToken();
return doWget( argv );
}
public boolean doWget ( String [] args ) throws Exception {
System.out.println(httpRequest);
System.out.println(proxyHost);
System.out.println(ftpPort);
urlConnection = setupProxy ( args );
if (!nonverbose) {
System.out.println("Connecting to " + httpRequest + "...");
if(
0==httpRequest.compareTo("http://www.p2p.wrox.com/listindex.asp") ) //
hangs
return false;
if(
0==httpRequest.compareTo("http://www.soton.ac.uk/~chst/direct.htm") )
// hangs
return false;
if(
0==httpRequest.compareTo("https://www.ahamembership.com/assoc6/k.cgi?p=10-TX&acct_code=TX004-10TX-T")
) // security exception
return false;
if(
0==httpRequest.compareTo("https://www25.hway.net/onl261/cgi-local/sgx/shop.cgi?page=order.html&afnum=21")
) // security exception
return false;
if( 0==httpRequest.compareTo("https://grc.com/x/ne.dll?bh0bkyd2") )
// security exception
return false;
}
try
{
DataOutputStream printout;
DataInputStream input;
urlConnection.setDoInput (true);
urlConnection.setUseCaches (false);
urlConnection.setRequestProperty("Accept","text/xml,text/*,text/html");
urlConnection.setRequestProperty("Cache-Control","no-cache");
if (null != strXML) // add XML data as HTTP payload
{ System.out.println("Adding XML...");
// Send POST output.
printout = new DataOutputStream (urlConnection.getOutputStream ());
String content =
"CoNUM=" + URLEncoder.encode ("2") +
"&PASSWORD=" + URLEncoder.encode ("1");
String msg;
msg = "<?xml version=" + "\"" + "1.0" + "\"" + "?>";
msg = msg + "</XML>";
content = msg;
System.out.println( " --- XML to Web Server ---\r\r" + content );
printout.writeBytes (content);
printout.flush ();
printout.close ();
}
}
catch (MalformedURLException me)
{
System.err.println("MalformedURLException: " + me);
}
catch (IOException ioe)
{
System.err.println("IOException: " + ioe.getMessage());
}
if( !readHttp() )
return false;
closeAll();
return true;
}
private void getOptions( String[] args ) throws Exception {
for (int i=0; i<args.length; i++) {
if (args.equals("-h")) {
StringTokenizer st = new StringTokenizer(args[i+1], ":");
int count=0;
while (st.hasMoreTokens()) {
if (count == 0 ) {
proxyHost=st.nextToken();
}
if (count == 1) {
proxyPort=st.nextToken();
}
count++;
}
if (proxyPort == null) {
proxyPort = "80";
}
i++;
notAssigned=false;
}
if (args.equals("-u")) {
username=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-p")) {
password=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-t")) {
proxyType=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-post")) {
formValues=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-method")) {
formMethod=args[i+1];
i++;
notAssigned=false;
}
if( args.equals("-xml") ) // get XML file
{ strXML = new String("<XML></XML>");
}
if (proxyHost != null && ftpTrue==true) {
if (!nonverbose) {
System.err.println("Proxy and Ftp cannot coexist use -h or -ftp");
} else {
throw new Exception("Proxy and Ftp cannot coexist use -h or
-ftp");
}
return;
}
if (notAssigned) {
httpRequest=args;
if (httpRequest.substring(0, 5).equalsIgnoreCase("https")) {
https=true;
}
}
notAssigned=true;
}
}
/** Main invoked from the prompt.
* @param args Arguments from the Stdin
* @throws Exception Throws Exception
*/
static String[] urls = {"http://www.youart.net/",
"http://www.microsoft.net/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.cnn.com/"};
public static void main ( String[] args ) throws Exception {
for( int e=0; e<urls.length; e++)
{ Leaky wget = new Leaky();
wget.doWget( urls[e] );
String result = wget.getOutput();
System.out.println( "page has " + result.length() + " characters" );
wget.zeroMem();
wget=null;
System.gc();
System.gc();
System.gc();
}
// memory is leaked at this point. Next memory is magically returned
if we sleep awhile.
for( int s=0; s<60; s++ ) {
try{ Thread.sleep(60000);}catch(Exception e){}
System.gc();
}
}
amount of calling System.gc(); will clean it up. OK for small apps but
I am writing one that downloads 100 or so pages synchronously. OK
unless I experience several clients asking my server to do this at
once. Then Java gives the almost useless OutOfMemoryError. So much for
Garbage Collection. At this point GC just means random
non-deterministic memory management and means, unlike in C++, I cannot
achieve a robust server application. How can Java justify giving
OutOfMemoryError when NO REFERENCES ARE HELD IN MY PROGRAM!!!! I guess
URLConnection must have some internal static buggy code.
Any ideas how to get URLConnection to stop hanging onto memory?
Here's some test code below.
TimJowers
/**
* Sample memory
*/
import java.net.*;
import java.io.*;
import java.util.*;
import java.security.*;
public class Leaky {
public String strXML = null;
private String proxyHost=null, proxyPort=null, username=null,
password=null,
httpRequest=null, base64Encoded=null, proxyType="2",
formValues=null, formMethod="", optionFile=null;
private URL url=null;
private URLConnection urlConnection=null;
private InputStream is=null;
private File file=null;
private FileOutputStream out=null;
private int ftpPort=21;
private boolean notAssigned = true,
ftpTrue=false, ftpPassive=false, ftpAscii=false,
https=false, nonverbose=true, post=false, booleanOptionFile=false;
private StringBuffer sbuf = null;
private byte[] bytesRead = new byte[4096];
protected void zeroMem()
{
strXML = null;
proxyHost=null; proxyPort=null; username=null; password=null;
httpRequest=null; base64Encoded=null;
formValues=null;
formMethod=""; optionFile=null;
url=null;
urlConnection=null;
is=null;
file=null;
out=null;
sbuf = null;
bytesRead = null;
}
public URLConnection setupProxy ( String [] args ) throws Exception
{
getOptions(args);
if (https) {
if (!nonverbose) {
System.out.println("Using https communication");
}
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("http.keepAlive", "false");
System.setProperty( "java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol" );
}
if (formMethod != null && formMethod.equalsIgnoreCase("get")) {
httpRequest = httpRequest + "?" + encodeHttpString(formValues);
}
try {
url = new URL(httpRequest);
} catch (MalformedURLException e) {
if (!nonverbose) {
System.err.println("Malformed URL, must be
http://somehost[/file]");
} else {
throw new Exception("Malformed URL, must be
http://somehost[/file]");
}
return null;
}
if (proxyHost != null) {
if (proxyType.equals("1") || proxyType.equals("3")) {
System.getProperties().put( "proxySet", "true" );
System.getProperties().put( "proxyHost", proxyHost);
System.getProperties().put( "proxyPort", proxyPort);
} else {
if (proxyType.equals("4")) {
System.getProperties().put( "socksProxySet", "true");
System.getProperties().put( "socksProxyHost", proxyHost);
System.getProperties().put( "SocksProxyPort" , proxyPort);
} else {
if (proxyType.equals("5")) {
System.getProperties().put( "ftpProxySet", "true" );
System.getProperties().put( "ftpProxyHost", proxyHost );
System.getProperties().put( "ftpProxyPort", proxyPort );
} else {
System.getProperties().put("firewallSet", "true");
System.getProperties().put("firewallHost", proxyHost);
System.getProperties().put("firewallPort", proxyPort);
System.getProperties().put("http.proxyHost", proxyHost);
System.getProperties().put("http.proxyPort", proxyPort);
}}}
if (https && proxyHost != null) {
System.getProperties().put("https.proxyHost", proxyHost);
System.getProperties().put("https.proxyPort", proxyPort);
}
}
try {
urlConnection = url.openConnection();
} catch (IOException e) {
if (!nonverbose) {
System.err.println("Error opening URL connection to " +
httpRequest);
} else {
throw new Exception("Error opening URL Connection to " +
httpRequest);
}
return null;
}
if (proxyHost != null) {
Base64 base64 = new Base64(username + ":" + password);
base64.encode();
base64Encoded = "Basic " + base64.getOutgoing();
urlConnection.setRequestProperty("Proxy-Connection","Keep-Alive");
if (proxyType.equals("3")) {
urlConnection.setRequestProperty("Authorization",
base64Encoded);
} else {
urlConnection.setRequestProperty("Proxy-Authorization",
base64Encoded);
}
}
return urlConnection;
}
public boolean doWget ( String args ) throws Exception {
// if args are all on one string then break into an array of strings
StringTokenizer strTok = new StringTokenizer( args );
String []argv = new String[ strTok.countTokens() ];
for(int i=0; strTok.hasMoreTokens(); i++ )
argv = strTok.nextToken();
return doWget( argv );
}
public boolean doWget ( String [] args ) throws Exception {
System.out.println(httpRequest);
System.out.println(proxyHost);
System.out.println(ftpPort);
urlConnection = setupProxy ( args );
if (!nonverbose) {
System.out.println("Connecting to " + httpRequest + "...");
if(
0==httpRequest.compareTo("http://www.p2p.wrox.com/listindex.asp") ) //
hangs
return false;
if(
0==httpRequest.compareTo("http://www.soton.ac.uk/~chst/direct.htm") )
// hangs
return false;
if(
0==httpRequest.compareTo("https://www.ahamembership.com/assoc6/k.cgi?p=10-TX&acct_code=TX004-10TX-T")
) // security exception
return false;
if(
0==httpRequest.compareTo("https://www25.hway.net/onl261/cgi-local/sgx/shop.cgi?page=order.html&afnum=21")
) // security exception
return false;
if( 0==httpRequest.compareTo("https://grc.com/x/ne.dll?bh0bkyd2") )
// security exception
return false;
}
try
{
DataOutputStream printout;
DataInputStream input;
urlConnection.setDoInput (true);
urlConnection.setUseCaches (false);
urlConnection.setRequestProperty("Accept","text/xml,text/*,text/html");
urlConnection.setRequestProperty("Cache-Control","no-cache");
if (null != strXML) // add XML data as HTTP payload
{ System.out.println("Adding XML...");
// Send POST output.
printout = new DataOutputStream (urlConnection.getOutputStream ());
String content =
"CoNUM=" + URLEncoder.encode ("2") +
"&PASSWORD=" + URLEncoder.encode ("1");
String msg;
msg = "<?xml version=" + "\"" + "1.0" + "\"" + "?>";
msg = msg + "</XML>";
content = msg;
System.out.println( " --- XML to Web Server ---\r\r" + content );
printout.writeBytes (content);
printout.flush ();
printout.close ();
}
}
catch (MalformedURLException me)
{
System.err.println("MalformedURLException: " + me);
}
catch (IOException ioe)
{
System.err.println("IOException: " + ioe.getMessage());
}
if( !readHttp() )
return false;
closeAll();
return true;
}
private void getOptions( String[] args ) throws Exception {
for (int i=0; i<args.length; i++) {
if (args.equals("-h")) {
StringTokenizer st = new StringTokenizer(args[i+1], ":");
int count=0;
while (st.hasMoreTokens()) {
if (count == 0 ) {
proxyHost=st.nextToken();
}
if (count == 1) {
proxyPort=st.nextToken();
}
count++;
}
if (proxyPort == null) {
proxyPort = "80";
}
i++;
notAssigned=false;
}
if (args.equals("-u")) {
username=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-p")) {
password=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-t")) {
proxyType=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-post")) {
formValues=args[i+1];
i++;
notAssigned=false;
}
if (args.equals("-method")) {
formMethod=args[i+1];
i++;
notAssigned=false;
}
if( args.equals("-xml") ) // get XML file
{ strXML = new String("<XML></XML>");
}
if (proxyHost != null && ftpTrue==true) {
if (!nonverbose) {
System.err.println("Proxy and Ftp cannot coexist use -h or -ftp");
} else {
throw new Exception("Proxy and Ftp cannot coexist use -h or
-ftp");
}
return;
}
if (notAssigned) {
httpRequest=args;
if (httpRequest.substring(0, 5).equalsIgnoreCase("https")) {
https=true;
}
}
notAssigned=true;
}
}
/** Main invoked from the prompt.
* @param args Arguments from the Stdin
* @throws Exception Throws Exception
*/
static String[] urls = {"http://www.youart.net/",
"http://www.microsoft.net/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.talkbackforum.com/", "http://www.unitedswe.com/",
"http://www.nbc.com/", "http://www.abc.com/",
"http://www.cbs.com/", "http://www.bbc.com/",
"http://www.ebay.com/", "http://www.yahoo.com/",
"http://www.ncr.com/", "http://www.ibm.com/",
"http://www.ford.com/", "http://www.cisco.com/",
"http://www.honda.com/", "http://www.toyota.com/",
"http://www.cnn.com/"};
public static void main ( String[] args ) throws Exception {
for( int e=0; e<urls.length; e++)
{ Leaky wget = new Leaky();
wget.doWget( urls[e] );
String result = wget.getOutput();
System.out.println( "page has " + result.length() + " characters" );
wget.zeroMem();
wget=null;
System.gc();
System.gc();
System.gc();
}
// memory is leaked at this point. Next memory is magically returned
if we sleep awhile.
for( int s=0; s<60; s++ ) {
try{ Thread.sleep(60000);}catch(Exception e){}
System.gc();
}
}