Continually-running Applet has memory leaks - how do I plug them?

P

Phil Powell

import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;


/**
* @version JDK 1.3
* @author Phil Powell
*/

/*---------------------------------------------------------------------------------------------
* ParseNews will receive a Phil-homegrown XML-like script from a PHP
file, parse through it,
* and will display each news item within the applet. The "View News"
button, upon being
* pressed, will perform an AppletContext showDocument action to go to
the URL formed by the
* passed ID per Vector iteration. News items will continually scroll
from bottom to top and
* then revert back to the first one
*
* Created 2/1/2003
*--------------------------------------------------------------------------------------------*/


public class ParseNews extends Applet {

// INITIALIZE VARS AND VAR SCOPE
protected Vector parseVector = new Vector();
protected Thread scrollThread = null;
protected ActionListener al = null;
private int xpos = 0, ypos = 0, index = 0;
private boolean hasStartedScroll = false, hasAddedAction = false;
private Button newsButton = new Button("View News");
private Panel scrollPanel, buttonPanel;

/*----------------------------------------------------------------------------------
* Vector method parser will return a vector of a 3-item array
containing the id,
* shortdescription and ranking of what was passed from the PHP
script
*
*----------------------------------------------------------------------------------*/

private Vector parser(String stuff) {
// STUFF
}

/*------------------------------------------------------------------------------------------
* Vector method sortedVector will sort the vector created by parser
into numerical order
* according to the ranking value found as the third element of each
3-item array found in
* each vector element
*
*------------------------------------------------------------------------------------------*/

private Vector sortedVector(Vector vectorToSort) {
// STUFF
}

// BUBBLE SORT INTEGER ARRAY METHOD - IN LIEU OF M$ NOT ALLOWING FOR
JAVA.UTIL.ARRAYS - GRRRR
private int[] mySortedArray(int[] origArray) {
// STUFF
}


/*------------------------------------------------------------------------------------------
* unescapeHTML String method will convert ASCII characters to their
"funky" equivalent.
*
* originally created by Rene Gagnon at
http://www.rgagnon.com/javadetails/java-0307.html
* Modified by Phil Powell on 2/2/2003
*
*-----------------------------------------------------------------------------------------*/

public static String unescapeHTML(String schtuff) {
String[][] asciiArray =
{{"&lt;", "<"}, {"&gt;", ">" }, {"&amp;", "&" }, {"&quot;", "\""},
{"&agrave;", "à"},
{"&Agrave;", "À"}, {"&acirc;", "â"}, {"&auml;", "ä"}, {"&Auml;",
"Ä"}, {"&Acirc;", "Â"},
{"&aring;", "å"}, {"&Aring;", "Å"}, {"&aelig;", "æ"}, {"&AElig;",
"Æ"}, {"&ccedil;", "ç"},
{"&Ccedil;", "Ç"}, {"&eacute;", "é"}, {"&Eacute;", "É"},
{"&egrave;", "è"},
{"&Egrave;", "È"}, {"&ecirc;", "ê"}, {"&Ecirc;", "Ê"}, {"&euml;",
"ë"}, {"&Euml;", "Ë"},
{"&iuml;", "ï"}, {"&Iuml;", "Ï"}, {"&ocirc;", "ô"}, {"&Ocirc;",
"Ô"}, {"&ouml;", "ö"},
{"&Ouml;", "Ö"}, {"&oslash;", "ø"}, {"&Oslash;", "Ø"}, {"&szlig;",
"ß"},
{"&ugrave;", "ù"}, {"&Ugrave;", "Ù"}, {"&ucirc;", "û"},
{"&Ucirc;", "Û"},
{"&uuml;", "ü"}, {"&Uuml;", "Ü"}, {"&nbsp;", " "}, {"&reg;",
"\u00a9"}, {"&copy;", "\u00ae"},
{"&euro;", "\u20a0"}
};
int flag = -1, ampIndex = -1;
if (schtuff.indexOf("&") >= 0) {
if (schtuff.indexOf(";") > schtuff.indexOf("&")) {
String asciiStuff = schtuff.substring(schtuff.indexOf("&"),
schtuff.indexOf(";") + 1);
ampIndex = schtuff.indexOf("&");
while (asciiStuff.substring(1, asciiStuff.length()).indexOf("&")
ampIndex = schtuff.indexOf("&", ampIndex + 1);
asciiStuff = asciiStuff.substring(1, asciiStuff.length()).trim();
}
for (int j = 0; j < asciiArray.length; j++) {
if (asciiArray[j][0].equals(asciiStuff)) {
flag = j;
break;
}
}
if (flag >= 0) {
schtuff = schtuff.substring(0, ampIndex) + asciiArray[flag][1] +
schtuff.substring(schtuff.indexOf(";") + 1,
schtuff.length());
return unescapeHTML(schtuff); // RECURSIVE
}
}
return schtuff;
} else {
return schtuff.trim();
}
}

// INITIALIZE APPLET, RETRIEVE VALUES FROM PHP SCRIPT AND SORT INTO
VECTOR

public void init() {
String stuff = null;
try {
URL url = new URL(getParameter("url"));
URLConnection conn = url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
conn.setRequestProperty("Content-type", "text/html");
BufferedReader fromURL = new BufferedReader(new
InputStreamReader(conn.getInputStream()));
stuff = fromURL.readLine();
// CLOSE CONNECTION
fromURL.close();
fromURL = null;
conn = null;
} catch (Exception e) {
parseVector.addElement(new String[]{"0", "Could not connect to
retrieve news", "0"});
}
if (stuff != null && stuff != "") {
parseVector = parser(stuff);
} else if (parseVector.size() == 0) {
parseVector.addElement(new String[]{"0", "No current news found",
"0"});
}

setBackground(Color.black);
setForeground(Color.white);
setFont(new Font("Garamond", Font.BOLD, 10));
scrollPanel = new Panel();
scrollPanel.setVisible(false);
buttonPanel = new Panel();
buttonPanel.setBackground(Color.black);
buttonPanel.setForeground(Color.white);
newsButton.setBackground(Color.red);
newsButton.setForeground(Color.white);
// ONLY ADD THE "VIEW NEWS" BUTTON IF THERE IS NEWS TO VIEW!
if (((String[])parseVector.elementAt(0))[0] != "0") {
buttonPanel.add(newsButton);
} else {
buttonPanel.setVisible(false);
}
add(scrollPanel);
add(buttonPanel);

scrollThread = new Thread(new ScrollNews());
scrollThread.start();

}

/*------------------------------------------------------------------------------------------
* Reinitialize value of the ActionListener object for the "View
News" button, along with
* display news item, with the "scrolling" effect handled by the
runnable class ScrollNews
*-----------------------------------------------------------------------------------------*/

public void paint(Graphics g) {

FontMetrics fm = g.getFontMetrics();
((String[])parseVector.elementAt(index))[1] =
unescapeHTML(((String[])parseVector.elementAt(index))[1]);
xpos = (getSize().width -
fm.stringWidth(((String[])parseVector.elementAt(index))[1])) / 2;
if (ypos <= 0) {
g.drawString("", 0, 0); // CLEAR THE APPLET
ypos = getSize().height;
hasAddedAction = false;
if (((String[])parseVector.elementAt(0))[0] != "0")
newsButton.removeActionListener(al);
if (index < parseVector.size() - 1 && hasStartedScroll) {
index++;
} else if (index > 0) {
index = 0;
hasStartedScroll = false;
}
}
if (((String[])parseVector.elementAt(0))[0] != "0" &&
!hasAddedAction) {
hasAddedAction = true;
al = new ViewNews("http://valsignalandet.com/cgi-bin/cgiwrap/ppowell/news.cgi?id="
+
((String[])parseVector.elementAt(index))[0]);
newsButton.addActionListener(al);
}

g.drawString(((String[])parseVector.elementAt(index))[1], xpos,
ypos);
hasStartedScroll = true;

}



class ScrollNews implements Runnable {

public void run() {
while (true) {
ypos = ypos - 1;
ParseNews.this.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
}
}

}

class ViewNews implements ActionListener {

private String urlString = "";

public ViewNews(String urlString) {
this.urlString = urlString;
}

public void actionPerformed(ActionEvent e) {
try {
ParseNews.this.getAppletContext().showDocument(new
URL(urlString));
} catch (Exception oops) {
System.out.println("could not go to " + urlString);
oops.printStackTrace();
}
}

}

}


The following applet I wrote had run just fine on my website until
sometime today, when it suddenly started running at an extremely slow
rate. I tried everything I could think of, including garbage
collection, to alleviate the problem, to no avail.

I am suspecting a memory leak somewhere but I cannot discern where.
Can anyone with more Java knowledge out there discern this for me or
at least tell me what steps I should be taking in my code to prevent
memory leaks for a continually-running applet?

Thanx
Phil
 
T

tollek

do you realy think that anyone would like to read and think over so long
code?

memory leak? you should check the expression 'garbage collector'

/tollek
 
A

Andrew Thompson

"Phil Powell" ...
| import java.io.*;

The code you supplied does not compile.
Besides the lines that wrap, there are
three methods that are not implemented.

You should also take efforts to ensure
that your code is the smallest compilable
example that demonstrates the problem.

| * originally created by Rene Gagnon at
| http://www.rgagnon.com/javadetails/java-0307.html
| * Modified by Phil Powell on 2/2/2003

Perhaps you should go back to the working
original, and start afresh.

.....
| The following applet I wrote had run just fine on my website until
| sometime today, when it suddenly started running at an extremely slow
| rate. I tried everything I could think of, including garbage
| collection, to alleviate the problem, to no avail.
|
| I am suspecting a memory leak somewhere but I cannot discern where.

What exactly makes you suspect that?
System monitors, or wild waving
about of arms?

| Can anyone with more Java knowledge out there discern this for me

Have you tried Elance?
 
F

Filip Larsen

Phil Powell wrote
The following applet I wrote had run just fine on my website
until sometime today, when it suddenly started running at an
extremely slow rate.

I cannot help you with that for the reasons other people have already
stated

However, I couldn't help noticing your "unescapeHTML" method. That
implementation is very inefficient, searching multiple times for the
same character and copying the whole string on every replace. You may
want to consider using something that expand entities in "one pass", for
instance

import java.util.HashMap;
import java.util.Map;

public class EntityReplacer {

/**
* Add entity value to the map.
* @param entity entity without ampersand and semicolon
* @param value value of the entity
*/
public void addEntity(String entity, String value) {
entities.put(entity,value);
}

/**
* Expand known entities in an xml string.
* Unknown entities are not expanded.
*/
public String expandEntities(String xml) {
StringBuffer result = null;
while (true) {
int start = xml.indexOf('&');
int end = xml.indexOf(';',start);
if (start < 0 || end < 0) {
break;
}
if (result == null) {
result = new StringBuffer();
}
result.append(xml.substring(0,start));
String entity = xml.substring(start+1,end);
result.append(replace(entity));
xml = xml.substring(end+1);
}
if (result == null) {
return xml;
}
result.append(xml);
return result.toString();
}

private static final Map standardEntities = new HashMap();
static {
standardEntities.put("amp","&");
standardEntities.put("lt","<");
standardEntities.put("gt",">");
// and so on ..
}

private Map entities = new HashMap(standardEntities);

private String replace(String entity) {
String value = (String) entities.get(entity);
return value != null ? value : '&'+entity+';';
}
}


If you are using Java 1.1 or earlier you have to use Hashtable instead
of Map and HashMap. For illustration, I have added a method to add
custom entities to the entity map; you can of course add other methods
for entity management if needed.


Regards,
 
M

Mark Haase

or
at least tell me what steps I should be taking in my code to prevent
memory leaks for a continually-running applet?

Don't lose pointers to objects. Set them to null when you're done with
them.

Keep in mind that Java eventually finds all orphaned objects and
releases them, so a memory leak is pretty difficult to cause -- a true
memory leak would be a problem with java.

Having said that, GC in java takes a finite time to run and only runs
once every so often. So its totally possible that if you're running
through some sort of loop where you continually create objects very
fast, or --worse yet-- create complex object graphs at very high speed,
then you can definitely outrun the GC and use up your memory. At that
point, the application will likely get very slow, and you will also get
OutOfMemoryErrors.
 
K

ketil v

Phil Powell skrev:
The following applet I wrote had run just fine on my website until
sometime today, when it suddenly started running at an extremely slow
rate. I tried everything I could think of, including garbage
collection, to alleviate the problem, to no avail.

I am suspecting a memory leak somewhere but I cannot discern where.
Can anyone with more Java knowledge out there discern this for me or
at least tell me what steps I should be taking in my code to prevent
memory leaks for a continually-running applet?

Thanx
Phil

I've had similar problems on the earlier versions of Java 1.3.1 and earlier.
solved it by simply upgrading to Java 1.4.2 - it got a better system for
handling such issues.

I know this solution sounds simple, but look at SUNs changelog for the
different Java's and you will find that they have done a lot of work on
this.
 
R

Robert Olofsson

: I am suspecting a memory leak somewhere but I cannot discern where.
Get a profiler and find out?

: Can anyone with more Java knowledge out there discern this for me or
: at least tell me what steps I should be taking in my code to prevent
: memory leaks for a continually-running applet?

make sure you close all streams, resultsets...
make sure you dispose/flush all windows, graphics and images when you
are finished with them.

Make sure you dont continously put new things into static hash/list.

/robo
 
P

Phil Powell

Andrew Thompson said:
"Phil Powell" ...
| import java.io.*;

The code you supplied does not compile.
Besides the lines that wrap, there are
three methods that are not implemented.

You should also take efforts to ensure
that your code is the smallest compilable
example that demonstrates the problem.

| * originally created by Rene Gagnon at
| http://www.rgagnon.com/javadetails/java-0307.html
| * Modified by Phil Powell on 2/2/2003

Perhaps you should go back to the working
original, and start afresh.

....
| The following applet I wrote had run just fine on my website until
| sometime today, when it suddenly started running at an extremely slow
| rate. I tried everything I could think of, including garbage
| collection, to alleviate the problem, to no avail.
|
| I am suspecting a memory leak somewhere but I cannot discern where.

What exactly makes you suspect that?
System monitors, or wild waving
about of arms?

| Can anyone with more Java knowledge out there discern this for me

Have you tried Elance?

Are you always this helpful or am I just the lucky one to be so berated?

Phil
 
P

Phil Powell

Filip Larsen said:
Phil Powell wrote


I cannot help you with that for the reasons other people have already
stated

However, I couldn't help noticing your "unescapeHTML" method. That
implementation is very inefficient, searching multiple times for the
same character and copying the whole string on every replace. You may
want to consider using something that expand entities in "one pass", for
instance

import java.util.HashMap;
import java.util.Map;

public class EntityReplacer {

/**
* Add entity value to the map.
* @param entity entity without ampersand and semicolon
* @param value value of the entity
*/
public void addEntity(String entity, String value) {
entities.put(entity,value);
}

/**
* Expand known entities in an xml string.
* Unknown entities are not expanded.
*/
public String expandEntities(String xml) {
StringBuffer result = null;
while (true) {
int start = xml.indexOf('&');
int end = xml.indexOf(';',start);
if (start < 0 || end < 0) {
break;
}
if (result == null) {
result = new StringBuffer();
}
result.append(xml.substring(0,start));
String entity = xml.substring(start+1,end);
result.append(replace(entity));
xml = xml.substring(end+1);
}
if (result == null) {
return xml;
}
result.append(xml);
return result.toString();
}

private static final Map standardEntities = new HashMap();
static {
standardEntities.put("amp","&");
standardEntities.put("lt","<");
standardEntities.put("gt",">");
// and so on ..
}

private Map entities = new HashMap(standardEntities);

private String replace(String entity) {
String value = (String) entities.get(entity);
return value != null ? value : '&'+entity+';';
}
}


If you are using Java 1.1 or earlier you have to use Hashtable instead
of Map and HashMap. For illustration, I have added a method to add
custom entities to the entity map; you can of course add other methods
for entity management if needed.


Regards,

Takk så meget.. I wound up trying a trick by changing "unescapeHTML"
from "public static String" to "public synchronized static String" and
for a couple of days it worked, suddenly only to lock up people's
resources again no matter what browser they use.

I am studying the class you wrote and with my limited Java knowledge
will take a while to absorb but I'll see what happens, thanx!

Phil
 
P

Phil Powell

ketil v said:
Phil Powell skrev:


I've had similar problems on the earlier versions of Java 1.3.1 and earlier.
solved it by simply upgrading to Java 1.4.2 - it got a better system for
handling such issues.

I know this solution sounds simple, but look at SUNs changelog for the
different Java's and you will find that they have done a lot of work on
this.

That would be an impractical solution, because this is an applet, and
that would mean millions of users out there would have to self-upgrade
to Java 1.4.2 to view my site :(

I changed one of my recursive methods to a synchronized static
recursive method and it worked for a couple of days.. and that was it.
:(

Phil
 
A

Andrew Thompson

"Phil Powell" ...
"Andrew Thompson" ...

Are you always this helpful or am I just the lucky one to be so berated?

Berated?! You obviously have not read
many of my posts if you think I was
berating you.

The same could be said of your sarcastic
question 'always this helpful?' If you'd read
my posts you would have seen that my
responses cover a wide range of responses,
depending on the quality of the question.

I note that you still have not bothered to
supply compilable code, and if you cannot
recognise the good bits of advice as such,
I see no point in wasting more time on you.
There are others more deserving.

Good luck.
 
P

Phil Powell

Andrew Thompson said:
"Phil Powell" ...

Berated?! You obviously have not read
many of my posts if you think I was
berating you.

The same could be said of your sarcastic
question 'always this helpful?' If you'd read
my posts you would have seen that my
responses cover a wide range of responses,
depending on the quality of the question.

I note that you still have not bothered to
supply compilable code, and if you cannot
recognise the good bits of advice as such,
I see no point in wasting more time on you.
There are others more deserving.

Good luck.

You wasted my time by forcing me to read this. I could easily supply
compilable code and in fact, will do so now, not for your benefit but
hopefully someone more helpful and more understanding of the needs of
others rather than your superior intellect.

Please don't waste your time (or mine) replying. Spend it more
worthily by understanding how to interact with other humans.

no one deserves your drivel.

Phil

import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;


/**
* @version JDK 1.3
* @author Phil Powell
*/

/*---------------------------------------------------------------------------------------------
* ParseNews will receive a Phil-homegrown XML-like script from a PHP
file, parse through it,
* and will display each news item within the applet. The "View News"
button, upon being
* pressed, will perform an AppletContext showDocument action to go to
the URL formed by the
* passed ID per Vector iteration. News items will continually scroll
from bottom to top and
* then revert back to the first one
*
* Created 2/1/2003
*--------------------------------------------------------------------------------------------*/


public class ParseNews extends Applet {

// INITIALIZE VARS AND VAR SCOPE
protected Vector parseVector = new Vector();
protected Thread scrollThread = null;
protected ActionListener al = null;
private int xpos = 0, ypos = 0, index = 0;
private boolean hasStartedScroll = false, hasAddedAction = false;
private Button newsButton = new Button("View News");
private Panel scrollPanel, buttonPanel;

/*----------------------------------------------------------------------------------
* Vector method parser will return a vector of a 3-item array
containing the id,
* shortdescription and ranking of what was passed from the PHP
script
*
*----------------------------------------------------------------------------------*/

private Vector parser(String stuff) {
Vector parsedXHTML = new Vector();
String idSection = "", sdSection = "", rankingSection = "";
boolean hasNews = true;
// CHECK TO SEE IF THERE IS ANYTHING FROM THE PHP SCRIPT - IF NOT NO
NEWS.XML FOUND
if (stuff.length() > 0 && (stuff.indexOf("<ID>") < 0 ||
stuff.indexOf("<SHORTDESCRIPTION>") < 0 || stuff.indexOf("<RANKING>")
< 0))
hasNews = false;
while (stuff.length() > 0 && hasNews) {
String[] rowArray = new String[3];
idSection = stuff.substring(stuff.indexOf("<ID>") + 4,
stuff.indexOf("</ID>"));
sdSection = stuff.substring(stuff.indexOf("<SHORTDESCRIPTION>") +
18, stuff.indexOf("</SHORTDESCRIPTION>"));
rankingSection = stuff.substring(stuff.indexOf("<RANKING>") + 9,
stuff.indexOf("</RANKING>"));
if (stuff.indexOf("</RANKING>") + 10 < stuff.length()) {
stuff = stuff.substring(stuff.indexOf("</RANKING>") + 10,
stuff.length()).trim();
} else {
stuff = "";
}
rowArray[0] = idSection;
rowArray[1] = sdSection;
rowArray[2] = rankingSection;
parsedXHTML.addElement(rowArray);
}
if (!hasNews) parsedXHTML.addElement(new String[]{"0", "No news file
found", "0"});

if (((String[])parsedXHTML.elementAt(0))[0] != "0")
parsedXHTML = sortedVector(parsedXHTML); // SORT INTO ORDER OF
RANKING
return parsedXHTML;
}

/*------------------------------------------------------------------------------------------
* Vector method sortedVector will sort the vector created by parser
into numerical order
* according to the ranking value found as the third element of each
3-item array found in
* each vector element
*
*------------------------------------------------------------------------------------------*/

private Vector sortedVector(Vector vectorToSort) {
Vector mySortedVector = new Vector();
int[] rankingArray = new int[vectorToSort.size()];
for (int i = 0; i < vectorToSort.size(); i++) {
rankingArray =
Integer.parseInt(((String[])vectorToSort.elementAt(i))[2]);
}

// YOUR OWN SORT
rankingArray = mySortedArray(rankingArray);
for (int i = 0; i < rankingArray.length; i++) {
for (int j = 0; j < vectorToSort.size(); j++) {
if (Integer.parseInt(((String[])vectorToSort.elementAt(j))[2]) ==
rankingArray) {
mySortedVector.addElement(vectorToSort.elementAt(j));
break;
}
}
}
if (mySortedVector.size() > 0) {
return mySortedVector;
} else {
return vectorToSort;
}
}

// BUBBLE SORT INTEGER ARRAY METHOD - IN LIEU OF M$ NOT ALLOWING FOR
JAVA.UTIL.ARRAYS - GRRRR
private int[] mySortedArray(int[] origArray) {
int intTemp;
for (int i = 0; i < origArray.length - 1; i++) {
for (int j = i + 1; j < origArray.length; j++) {
if (origArray > origArray[j]) {
intTemp = origArray;
origArray = origArray[j];
origArray[j] = intTemp;
}
}
}
return origArray;
}


/*------------------------------------------------------------------------------------------
* unescapeHTML String method will convert ASCII characters to their
"funky" equivalent.
*
* originally created by Rene Gagnon at
http://www.rgagnon.com/javadetails/java-0307.html
* Modified by Phil Powell on 2/2/2003
*
*-----------------------------------------------------------------------------------------*/

public static String unescapeHTML(String schtuff) {
String[][] asciiArray =
{{"&lt;", "<"}, {"&gt;", ">" }, {"&amp;", "&" }, {"&quot;", "\""},
{"&agrave;", "à"},
{"&Agrave;", "À"}, {"&acirc;", "â"}, {"&auml;", "ä"}, {"&Auml;",
"Ä"}, {"&Acirc;", "Â"},
{"&aring;", "å"}, {"&Aring;", "Å"}, {"&aelig;", "æ"}, {"&AElig;",
"Æ"}, {"&ccedil;", "ç"},
{"&Ccedil;", "Ç"}, {"&eacute;", "é"}, {"&Eacute;", "É"},
{"&egrave;", "è"},
{"&Egrave;", "È"}, {"&ecirc;", "ê"}, {"&Ecirc;", "Ê"}, {"&euml;",
"ë"}, {"&Euml;", "Ë"},
{"&iuml;", "ï"}, {"&Iuml;", "Ï"}, {"&ocirc;", "ô"}, {"&Ocirc;",
"Ô"}, {"&ouml;", "ö"},
{"&Ouml;", "Ö"}, {"&oslash;", "ø"}, {"&Oslash;", "Ø"}, {"&szlig;",
"ß"},
{"&ugrave;", "ù"}, {"&Ugrave;", "Ù"}, {"&ucirc;", "û"},
{"&Ucirc;", "Û"},
{"&uuml;", "ü"}, {"&Uuml;", "Ü"}, {"&nbsp;", " "}, {"&reg;",
"\u00a9"}, {"&copy;", "\u00ae"},
{"&euro;", "\u20a0"}
};
int flag = -1, ampIndex = -1;
if (schtuff.indexOf("&") >= 0) {
if (schtuff.indexOf(";") > schtuff.indexOf("&")) {
String asciiStuff = schtuff.substring(schtuff.indexOf("&"),
schtuff.indexOf(";") + 1);
ampIndex = schtuff.indexOf("&");
while (asciiStuff.substring(1, asciiStuff.length()).indexOf("&")
ampIndex = schtuff.indexOf("&", ampIndex + 1);
asciiStuff = asciiStuff.substring(1, asciiStuff.length()).trim();
}
for (int j = 0; j < asciiArray.length; j++) {
if (asciiArray[j][0].equals(asciiStuff)) {
flag = j;
break;
}
}
if (flag >= 0) {
schtuff = schtuff.substring(0, ampIndex) + asciiArray[flag][1] +
schtuff.substring(schtuff.indexOf(";") + 1,
schtuff.length());
return unescapeHTML(schtuff); // RECURSIVE
}
}
return schtuff;
} else {
return schtuff.trim();
}
}

// INITIALIZE APPLET, RETRIEVE VALUES FROM PHP SCRIPT AND SORT INTO
VECTOR

public void init() {
String stuff = null;
try {
URL url = new URL(getParameter("url"));
URLConnection conn = url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
conn.setRequestProperty("Content-type", "text/html");
BufferedReader fromURL = new BufferedReader(new
InputStreamReader(conn.getInputStream()));
stuff = fromURL.readLine();
// CLOSE CONNECTION
fromURL.close();
fromURL = null;
conn = null;
} catch (Exception e) {
parseVector.addElement(new String[]{"0", "Could not connect to
retrieve news", "0"});
}
if (stuff != null && stuff != "") {
parseVector = parser(stuff);
} else if (parseVector.size() == 0) {
parseVector.addElement(new String[]{"0", "No current news found",
"0"});
}

setBackground(Color.black);
setForeground(Color.white);
setFont(new Font("Garamond", Font.BOLD, 10));
scrollPanel = new Panel();
scrollPanel.setVisible(false);
buttonPanel = new Panel();
buttonPanel.setBackground(Color.black);
buttonPanel.setForeground(Color.white);
newsButton.setBackground(Color.red);
newsButton.setForeground(Color.white);
// ONLY ADD THE "VIEW NEWS" BUTTON IF THERE IS NEWS TO VIEW!
if (((String[])parseVector.elementAt(0))[0] != "0") {
buttonPanel.add(newsButton);
} else {
buttonPanel.setVisible(false);
}
add(scrollPanel);
add(buttonPanel);

scrollThread = new Thread(new ScrollNews());
scrollThread.start();

}

/*------------------------------------------------------------------------------------------
* Reinitialize value of the ActionListener object for the "View
News" button, along with
* display news item, with the "scrolling" effect handled by the
runnable class ScrollNews
*-----------------------------------------------------------------------------------------*/

public void paint(Graphics g) {

FontMetrics fm = g.getFontMetrics();
//((String[])parseVector.elementAt(index))[1] =
// unescapeHTML(((String[])parseVector.elementAt(index))[1]);

System.out.println(((String[])parseVector.elementAt(index))[1]);

((String[])parseVector.elementAt(index))[1] =
java.net.URLEncoder.encode(((String[])parseVector.elementAt(index))[1]);
xpos = (getSize().width -
fm.stringWidth(((String[])parseVector.elementAt(index))[1])) / 2;
if (ypos <= 0) {
g.drawString("", 0, 0); // CLEAR THE APPLET
ypos = getSize().height;
hasAddedAction = false;
if (((String[])parseVector.elementAt(0))[0] != "0")
newsButton.removeActionListener(al);
if (index < parseVector.size() - 1 && hasStartedScroll) {
index++;
} else if (index > 0) {
index = 0;
hasStartedScroll = false;
}
}
if (((String[])parseVector.elementAt(0))[0] != "0" &&
!hasAddedAction) {
hasAddedAction = true;
al = new ViewNews("http://valsignalandet.com/cgi-bin/cgiwrap/ppowell/news.cgi?id="
+
((String[])parseVector.elementAt(index))[0]);
newsButton.addActionListener(al);
}

g.drawString(((String[])parseVector.elementAt(index))[1], xpos,
ypos);
hasStartedScroll = true;

}



class ScrollNews implements Runnable {

public void run() {
while (true) {
ypos = ypos - 1;
ParseNews.this.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
System.gc(); // GARBAGE COLLECTION - MIGHT HELP WITH POTENTIAL
MEMORY LEAK
}
}

}

class ViewNews implements ActionListener {

private String urlString = "";

public ViewNews(String urlString) {
this.urlString = urlString;
}

public void actionPerformed(ActionEvent e) {
try {
ParseNews.this.getAppletContext().showDocument(new
URL(urlString));
} catch (Exception oops) {
System.out.println("could not go to " + urlString);
oops.printStackTrace();
}
}

}

}
 
P

Phil Powell

Mark Haase said:
Don't lose pointers to objects. Set them to null when you're done with
them.

Keep in mind that Java eventually finds all orphaned objects and
releases them, so a memory leak is pretty difficult to cause -- a true
memory leak would be a problem with java.

Having said that, GC in java takes a finite time to run and only runs
once every so often. So its totally possible that if you're running
through some sort of loop where you continually create objects very
fast, or --worse yet-- create complex object graphs at very high speed,
then you can definitely outrun the GC and use up your memory. At that
point, the application will likely get very slow, and you will also get
OutOfMemoryErrors.

Following is the entire compilable code (per requests):

import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;


/**
* @version JDK 1.3
* @author Phil Powell
*/

/*---------------------------------------------------------------------------------------------
* ParseNews will receive a Phil-homegrown XML-like script from a PHP
file, parse through it,
* and will display each news item within the applet. The "View News"
button, upon being
* pressed, will perform an AppletContext showDocument action to go to
the URL formed by the
* passed ID per Vector iteration. News items will continually scroll
from bottom to top and
* then revert back to the first one
*
* Created 2/1/2003
*--------------------------------------------------------------------------------------------*/


public class ParseNews extends Applet {

// INITIALIZE VARS AND VAR SCOPE
protected Vector parseVector = new Vector();
protected Thread scrollThread = null;
protected ActionListener al = null;
private int xpos = 0, ypos = 0, index = 0;
private boolean hasStartedScroll = false, hasAddedAction = false;
private Button newsButton = new Button("View News");
private Panel scrollPanel, buttonPanel;

/*----------------------------------------------------------------------------------
* Vector method parser will return a vector of a 3-item array
containing the id,
* shortdescription and ranking of what was passed from the PHP
script
*
*----------------------------------------------------------------------------------*/

private Vector parser(String stuff) {
Vector parsedXHTML = new Vector();
String idSection = "", sdSection = "", rankingSection = "";
boolean hasNews = true;
// CHECK TO SEE IF THERE IS ANYTHING FROM THE PHP SCRIPT - IF NOT NO
NEWS.XML FOUND
if (stuff.length() > 0 && (stuff.indexOf("<ID>") < 0 ||
stuff.indexOf("<SHORTDESCRIPTION>") < 0 || stuff.indexOf("<RANKING>")
< 0))
hasNews = false;
while (stuff.length() > 0 && hasNews) {
String[] rowArray = new String[3];
idSection = stuff.substring(stuff.indexOf("<ID>") + 4,
stuff.indexOf("</ID>"));
sdSection = stuff.substring(stuff.indexOf("<SHORTDESCRIPTION>") +
18, stuff.indexOf("</SHORTDESCRIPTION>"));
rankingSection = stuff.substring(stuff.indexOf("<RANKING>") + 9,
stuff.indexOf("</RANKING>"));
if (stuff.indexOf("</RANKING>") + 10 < stuff.length()) {
stuff = stuff.substring(stuff.indexOf("</RANKING>") + 10,
stuff.length()).trim();
} else {
stuff = "";
}
rowArray[0] = idSection;
rowArray[1] = sdSection;
rowArray[2] = rankingSection;
parsedXHTML.addElement(rowArray);
}
if (!hasNews) parsedXHTML.addElement(new String[]{"0", "No news file
found", "0"});

if (((String[])parsedXHTML.elementAt(0))[0] != "0")
parsedXHTML = sortedVector(parsedXHTML); // SORT INTO ORDER OF
RANKING
return parsedXHTML;
}

/*------------------------------------------------------------------------------------------
* Vector method sortedVector will sort the vector created by parser
into numerical order
* according to the ranking value found as the third element of each
3-item array found in
* each vector element
*
*------------------------------------------------------------------------------------------*/

private Vector sortedVector(Vector vectorToSort) {
Vector mySortedVector = new Vector();
int[] rankingArray = new int[vectorToSort.size()];
for (int i = 0; i < vectorToSort.size(); i++) {
rankingArray =
Integer.parseInt(((String[])vectorToSort.elementAt(i))[2]);
}

// YOUR OWN SORT
rankingArray = mySortedArray(rankingArray);
for (int i = 0; i < rankingArray.length; i++) {
for (int j = 0; j < vectorToSort.size(); j++) {
if (Integer.parseInt(((String[])vectorToSort.elementAt(j))[2]) ==
rankingArray) {
mySortedVector.addElement(vectorToSort.elementAt(j));
break;
}
}
}
if (mySortedVector.size() > 0) {
return mySortedVector;
} else {
return vectorToSort;
}
}

// BUBBLE SORT INTEGER ARRAY METHOD - IN LIEU OF M$ NOT ALLOWING FOR
JAVA.UTIL.ARRAYS - GRRRR
private int[] mySortedArray(int[] origArray) {
int intTemp;
for (int i = 0; i < origArray.length - 1; i++) {
for (int j = i + 1; j < origArray.length; j++) {
if (origArray > origArray[j]) {
intTemp = origArray;
origArray = origArray[j];
origArray[j] = intTemp;
}
}
}
return origArray;
}


/*------------------------------------------------------------------------------------------
* unescapeHTML String method will convert ASCII characters to their
"funky" equivalent.
*
* originally created by Rene Gagnon at
http://www.rgagnon.com/javadetails/java-0307.html
* Modified by Phil Powell on 2/2/2003
*
*-----------------------------------------------------------------------------------------*/

public static String unescapeHTML(String schtuff) {
String[][] asciiArray =
{{"&lt;", "<"}, {"&gt;", ">" }, {"&amp;", "&" }, {"&quot;", "\""},
{"&agrave;", "à"},
{"&Agrave;", "À"}, {"&acirc;", "â"}, {"&auml;", "ä"}, {"&Auml;",
"Ä"}, {"&Acirc;", "Â"},
{"&aring;", "å"}, {"&Aring;", "Å"}, {"&aelig;", "æ"}, {"&AElig;",
"Æ"}, {"&ccedil;", "ç"},
{"&Ccedil;", "Ç"}, {"&eacute;", "é"}, {"&Eacute;", "É"},
{"&egrave;", "è"},
{"&Egrave;", "È"}, {"&ecirc;", "ê"}, {"&Ecirc;", "Ê"}, {"&euml;",
"ë"}, {"&Euml;", "Ë"},
{"&iuml;", "ï"}, {"&Iuml;", "Ï"}, {"&ocirc;", "ô"}, {"&Ocirc;",
"Ô"}, {"&ouml;", "ö"},
{"&Ouml;", "Ö"}, {"&oslash;", "ø"}, {"&Oslash;", "Ø"}, {"&szlig;",
"ß"},
{"&ugrave;", "ù"}, {"&Ugrave;", "Ù"}, {"&ucirc;", "û"},
{"&Ucirc;", "Û"},
{"&uuml;", "ü"}, {"&Uuml;", "Ü"}, {"&nbsp;", " "}, {"&reg;",
"\u00a9"}, {"&copy;", "\u00ae"},
{"&euro;", "\u20a0"}
};
int flag = -1, ampIndex = -1;
if (schtuff.indexOf("&") >= 0) {
if (schtuff.indexOf(";") > schtuff.indexOf("&")) {
String asciiStuff = schtuff.substring(schtuff.indexOf("&"),
schtuff.indexOf(";") + 1);
ampIndex = schtuff.indexOf("&");
while (asciiStuff.substring(1, asciiStuff.length()).indexOf("&")
ampIndex = schtuff.indexOf("&", ampIndex + 1);
asciiStuff = asciiStuff.substring(1, asciiStuff.length()).trim();
}
for (int j = 0; j < asciiArray.length; j++) {
if (asciiArray[j][0].equals(asciiStuff)) {
flag = j;
break;
}
}
if (flag >= 0) {
schtuff = schtuff.substring(0, ampIndex) + asciiArray[flag][1] +
schtuff.substring(schtuff.indexOf(";") + 1,
schtuff.length());
return unescapeHTML(schtuff); // RECURSIVE
}
}
return schtuff;
} else {
return schtuff.trim();
}
}

// INITIALIZE APPLET, RETRIEVE VALUES FROM PHP SCRIPT AND SORT INTO
VECTOR

public void init() {
String stuff = null;
try {
URL url = new URL(getParameter("url"));
URLConnection conn = url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
conn.setRequestProperty("Content-type", "text/html");
BufferedReader fromURL = new BufferedReader(new
InputStreamReader(conn.getInputStream()));
stuff = fromURL.readLine();
// CLOSE CONNECTION
fromURL.close();
fromURL = null;
conn = null;
} catch (Exception e) {
parseVector.addElement(new String[]{"0", "Could not connect to
retrieve news", "0"});
}
if (stuff != null && stuff != "") {
parseVector = parser(stuff);
} else if (parseVector.size() == 0) {
parseVector.addElement(new String[]{"0", "No current news found",
"0"});
}

setBackground(Color.black);
setForeground(Color.white);
setFont(new Font("Garamond", Font.BOLD, 10));
scrollPanel = new Panel();
scrollPanel.setVisible(false);
buttonPanel = new Panel();
buttonPanel.setBackground(Color.black);
buttonPanel.setForeground(Color.white);
newsButton.setBackground(Color.red);
newsButton.setForeground(Color.white);
// ONLY ADD THE "VIEW NEWS" BUTTON IF THERE IS NEWS TO VIEW!
if (((String[])parseVector.elementAt(0))[0] != "0") {
buttonPanel.add(newsButton);
} else {
buttonPanel.setVisible(false);
}
add(scrollPanel);
add(buttonPanel);

scrollThread = new Thread(new ScrollNews());
scrollThread.start();

}

/*------------------------------------------------------------------------------------------
* Reinitialize value of the ActionListener object for the "View
News" button, along with
* display news item, with the "scrolling" effect handled by the
runnable class ScrollNews
*-----------------------------------------------------------------------------------------*/

public void paint(Graphics g) {

FontMetrics fm = g.getFontMetrics();
//((String[])parseVector.elementAt(index))[1] =
// unescapeHTML(((String[])parseVector.elementAt(index))[1]);

System.out.println(((String[])parseVector.elementAt(index))[1]);

((String[])parseVector.elementAt(index))[1] =
java.net.URLEncoder.encode(((String[])parseVector.elementAt(index))[1]);
xpos = (getSize().width -
fm.stringWidth(((String[])parseVector.elementAt(index))[1])) / 2;
if (ypos <= 0) {
g.drawString("", 0, 0); // CLEAR THE APPLET
ypos = getSize().height;
hasAddedAction = false;
if (((String[])parseVector.elementAt(0))[0] != "0")
newsButton.removeActionListener(al);
if (index < parseVector.size() - 1 && hasStartedScroll) {
index++;
} else if (index > 0) {
index = 0;
hasStartedScroll = false;
}
}
if (((String[])parseVector.elementAt(0))[0] != "0" &&
!hasAddedAction) {
hasAddedAction = true;
al = new ViewNews("http://valsignalandet.com/cgi-bin/cgiwrap/ppowell/news.cgi?id="
+
((String[])parseVector.elementAt(index))[0]);
newsButton.addActionListener(al);
}

g.drawString(((String[])parseVector.elementAt(index))[1], xpos,
ypos);
hasStartedScroll = true;

}



class ScrollNews implements Runnable {

public void run() {
while (true) {
ypos = ypos - 1;
ParseNews.this.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
System.gc(); // GARBAGE COLLECTION - MIGHT HELP WITH POTENTIAL
MEMORY LEAK
}
}

}

class ViewNews implements ActionListener {

private String urlString = "";

public ViewNews(String urlString) {
this.urlString = urlString;
}

public void actionPerformed(ActionEvent e) {
try {
ParseNews.this.getAppletContext().showDocument(new
URL(urlString));
} catch (Exception oops) {
System.out.println("could not go to " + urlString);
oops.printStackTrace();
}
}

}

}


----

I don't know if that will help or not, but it's worth a try. I tried
every trick I know, to no avail at this point. Do note the line
"java.net.URLEncoder.encode()"

Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top