Huge Web App With Memory Leak in IE 6 - memory-leaks

I have a huge web app that is having issues with memory leak in IE 6.
Fixing a memory leak in a 5 line code sample that demonstrates the problem is easy.
But if I have a very huge application, where should a start from?

Check out Drip. That usually takes the guesswork out of IE memory leaks.
If for some reason Drip doesn't find it, take a close look at any JavaScript code that works with events. That is almost always the source of any significant memory leak in a browser.
Destroying a DOM element with handlers attached to it, without removing those handlers first, will prevent the memory associated with those handlers from being recovered.

Does the application use a lot of JavaScript?
If it does, then one thing I've found that helps for avoiding memory leaks is to make sure you're using a JavaScript framework such as Prototype or jQuery because they have tried and tested event-handling code that doesn't leak memory.
IE6 can also leak memory if you have circular references to DOM objects
Also try this JavaScript Memory Leak Detector and see if you can diagnose where the problem is

Here is how I solved the memory leak problem in IE7. The idea is to dispose/set to null all expando-properties on all DOM nodes at unloading the page. This worked for me. You may find it useful.
<!--[if lt IE 8]>
<script type="text/javascript">
function disposeAll() {
if (window.document.all) {
for (var index = 0; index < window.document.all.length; index++) {
try { dispose(window.document.all[index], []); } catch (e) { debugger; }
}
}
dispose(window.document.body, []);
dispose(window.document, []);
dispose(window, []);
window.disposeAll = null;
window.dispose = null;
window.onunload = null;
}
function dispose(something, map) {
if (something == null) return;
if (something.dispose && typeof (something.dispose) == 'function') {
try { something.dispose(); } catch (e) { debugger; }
}
map.push(something);
for (var key in something) {
var value = null;
try { value = something[key]; } catch (e) { };
if (value == null || value == dispose || value == disposeAll) continue;
var processed = null;
for (var index = 0; index < map.length; index++) {
if (map[index] === value) {
processed = value;
break;
}
}
if (processed != null) continue;
var constructor = value.constructor;
if (constructor == Object || constructor == Array) {
try { dispose(value, map); } catch (e) { debugger; }
}
if (constructor == Object || constructor == Array || constructor == Function) {
try { something[key] = null; } catch (e) { debugger; }
}
}
map.pop();
}
(function() {
var previousUnloadHandler = window.onunload;
if (previousUnloadHandler == null) {
window.onunload = disposeAll;
} else {
window.onunload = function() {
previousUnloadHandler.apply(this, arguments); // <== HERE YOU MAY WANT TO HAVE AN "IF" TO MAKE SURE THE ORIGINAL UNLOAD EVENT WASN'T CANCELLED
disposeAll();
previousUnloadHandler = null;
};
}
}());
</script>
<![endif]-->
You may want to remove all "debugger;" statements if you don't feel like dealing with some occasional exceptions.

Related

Prevent a new block from being attached to the same type if the target is used as a StatementInput

I basically have two types of blocks: a rule block and a fact block (just like in Prolog). They can both be attached to each other. The rule block expects two inputs of the type 'fact'.
However, it should not be possible to have multiple attached fact blocks as a single input. Therefore I had to set 'setNextStatement' to false whenever a fact block is attached as input of a rule block.
This is what I tried to do in the fact block:
this.setOnChange(function(changeEvent) {
if(changeEvent.type == Blockly.Events.MOVE) {
let prevBlock = this.getPreviousBlock();
if(prevBlock != null && prevBlock.type == "rule") {
let nextBlock = prevBlock.getNextBlock();
if((nextBlock != null && nextBlock != this) || (nextBlock == null)) {
this.setNextStatement(false);
}
} else {
this.setNextStatement(true);
}
}
});
And of course the rule block:
Blockly.Blocks['rule'] = {
init: function() {
this.appendDummyInput("RULE_DATA")
.appendField('Rule: ');
this.appendStatementInput('INPUT_HEAD')
.setCheck("fact")
.appendField("Head");
this.appendStatementInput('INPUT_BODY')
.setCheck("fact")
.appendField("Body");
...
This actually works, but when I separate a fact from the input part of a rule, I always get the following error:
Uncaught Error: Connection lists did not match in length.
at Blockly.BlockSvg.Blockly.Block.getMatchingConnection (blockly_compressed.js:1447)
at Blockly.InsertionMarkerManager.connectMarker_ (blockly_compressed.js:1125)
at Blockly.InsertionMarkerManager.showPreview_ (blockly_compressed.js:1118)
at Blockly.InsertionMarkerManager.maybeShowPreview_ (blockly_compressed.js:1117)
at Blockly.InsertionMarkerManager.update (blockly_compressed.js:1110)
at Blockly.BlockDragger.dragBlock (blockly_compressed.js:1130)
at Blockly.TouchGesture.Blockly.Gesture.startDraggingBlock_ (blockly_compressed.js:1177)
at Blockly.TouchGesture.Blockly.Gesture.updateIsDraggingBlock_ (blockly_compressed.js:1174)
at Blockly.TouchGesture.Blockly.Gesture.updateIsDragging_ (blockly_compressed.js:1176)
at Blockly.TouchGesture.Blockly.Gesture.updateFromEvent_ (blockly_compressed.js:1171)
Does somebody has any idea?
Hi you need is just override the getMatchingConnection function from blockly and comment the check in the function
window.Blockly.Block.prototype.getMatchingConnection = function(otherBlock, conn) {
var connections = this.getConnections_(true);
var otherConnections = otherBlock.getConnections_(true);
// if (connections.length !== otherConnections.length) {
// throw Error("Connection lists did not match in length.");
// }
for (var i = 0; i < otherConnections.length; i++) {
if (otherConnections[i] === conn) {
return connections[i];
}
}
return null;
};

Issues with ActiveXObject in Angular 7

I am developing a small page/router component on a website using Angular 7 and its CLI. At one point I need to check if the user has allowed flash, I do this by doing so:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-shockwave-flash"];
}
return hasFlash;
}
I found this off here, and it works great, but now as I am cleaning up my application I am noticing that Angular doesn't seem to like this, in fact, it says that ActiveXObject isn't defined, yet it still works.
Super confused...
I tried linking an actual flash object like so $('embed[type="application/x-shockwave-flash"]') or $('embed[type="application/x-shockwave-flash"]')[0] but had no luck, it always returned true.
I tried installing extra npm(s) including ones like activex-support and activex-data-support as well as their #types cousins. After setting them up I found out that they did nothing to help my case.
Here are the exact errors the CLI & VScode-Intellisense gave me:
VScode:
[ts] 'ActiveXObject' only refers to a type, but is being used as a value here. [2693]
any
CLI:
ERROR in src/app/games/games.component.ts(51,30): error TS2304: Cannot find name 'ActiveXObject'.
It doesn't throw this error when ran inside plain JS, but I've looked around and can't seem to figure out how to run pure JS inside Angular 2 (7). Also looked here with no luck.
Please help, completely lost here.
EDIT: Found the fix -->
The answer was here listed inside the comments (will need to make minor changes)(shown below)
change from:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-
shockwave-flash"];
}
return hasFlash;
}
to:
function checkFlash() {
var hasFlash = false;
try {
var flash =
navigator.mimeTypes &&
navigator.mimeTypes["application/x-shockwave-flash"]
? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin
: 0;
if (flash) hasFlash = true;
} catch (e) {
if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined)
hasFlash = true;
}
return hasFlash;
}
This issue with ActiveXObject can be solve as shown below:
Goto your tsconfig.json file and add the 'scripthost' library.
Then recompile your application.
"lib": [
"es2017",
"dom",
"scripthost"
]
The answer was here listed inside the comments (will need to make minor changes)(shown below)
change from:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-
shockwave-flash"];
}
return hasFlash;
}
to:
function checkFlash() {
var hasFlash = false;
try {
var flash =
navigator.mimeTypes &&
navigator.mimeTypes["application/x-shockwave-flash"]
? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin
: 0;
if (flash) hasFlash = true;
} catch (e) {
if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined)
hasFlash = true;
}
return hasFlash;
}

lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem

I try to put a file into a richtext but it crashes !
In my first code, I try to use directly "getFirstItem", in first time it was ok but now i try to use it again and it crashed.
In second time i pass with an object and it find my obj doesn't an richtextItem (instanceof) ???
I don't understand.
I have the message : "lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem" ?
Could you help me ?
public void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) throws NotesException {
lotus.domino.Session session = Utils.getSession();
lotus.domino.Database db = session.getCurrentDatabase();
lotus.domino.Document monDoc = db.getDocumentByUNID(idDocument);
lotus.domino.RichTextItem rtiNew = null;
try {
try {
if (monDoc != null) {
// if (monDoc.getFirstItem(nomRti) != null) {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.getFirstItem(nomRti);
// } else {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.createRichTextItem(nomRti);
// }
Object obj = null;
if (monDoc.getFirstItem(nomRti) != null) {
obj = monDoc.getFirstItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
} else {
obj = monDoc.createRichTextItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
}
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtiNew.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
}
} finally {
rtiNew.recycle();
monDoc.recycle();
db.recycle();
session.recycle();
}
} catch (Exception e) {
e.printStackTrace();
}
}
EDIT : I try to modify my code with yours advices but the items never considerate as richtextitem. It is my problem. I don't understand why, because in my field it is a richtext ! For it, the item can't do :
rtiNew = (lotus.domino.RichTextItem) item1;
because item1 not be a richtext !!!
I was trying to take all the fields and pass in the item one by one, and it never go to the obj instance of lotus.domini.RichTextItem....
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
// get next element from the Vector (returns java.lang.Object)
Object obj = items.elementAt(i);
// is the item a RichTextItem?
if (obj instanceof RichTextItem) {
// yes it is - cast it as such // it never go here !!
rt = (RichTextItem)obj;
} else {
// nope - cast it as an Item
item = (Item)obj;
}
}
A couple of things. First of all I would set up a util class method to handle the object recycling in a neater way:
public enum DominoUtil {
;
public static void recycle(Base... bases) {
for (Base base : bases) {
if (base != null) {
try {
base.recycle();
} catch (Exception e) {
// Do nothing
}
}
}
}
}
Secondly I would remove the reduntants try/catch blocks and simplify it like this:
private void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) {
Session session = DominoUtils.getCurrentSession();
Database db = session.getCurrentDatabase();
Document monDoc = null;
try {
monDoc = db.getDocumentByUNID(idDocument);
Item item = monDoc.getFirstItem(nomRti);
if (item == null) {
item = monDoc.createRichTextItem(nomRti);
} else if (item.getType() != Item.RICHTEXT) {
// The item is not a rich text item
// What are you going to do now?
}
RichTextItem rtItem = (RichTextItem) item;
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtItem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
} catch (NotesException e) {
throw new FacesException(e);
} finally {
DominoUtil.recycle(monDoc);
}
}
Finally, apart from the monDoc, you need not recycle anything else. Actually Session would be automatically recycled and anything beneath with it (so no need to recycle db, let alone the session!, good rule is don't recycle what you didn't instantiate), but it's not bad to keep the habit of keeping an eye on what you instantiate. If it were a loop with many documents you definitively want to do that. If you also worked with many items you would want to recycle them as early as possible. Anyway, considered the scope of the code it's sufficient like this. Obviously you would call DominoUtil.recycle directly from the try block. If you have multiple objects you can recycle them at once possibly by listing them in the reverse order you set them (eg. DominoUtil.recycle(item, doc, view)).
Also, what I think you miss is the check on the item in case it's not a RichTextItem - and therefore can't be cast. I put a comment where I think you should decide what to do before proceeding. If you let it like that and let the code proceed you will have the code throw an error. Always better to catch the lower level exception and re-throw a higher one (you don't want the end user to know more than it is necessary to know). In this case I went for the simplest thing: wrapped NotesException in a FacesException.

NodeJS Error Encapsulation

I am currently trying to handle exceptions and errors in a NodeJS app which will be used for critical information. I need a clean error management !
I've been wondering if there is something similar to Java Exceptions encapsulation.
I'm explaning.
In Java you can do something like that :
try {
// something that throws Exception
} catch (Throwable t) {
throw new Exception("My message", t);
}
That allows you to decide when to log your exception and you get the whole stack trace and call path !
I would like to know if there is a way to do the same in NodeJS because logging at every step seems not to be the right way of doing things.
Thank you.
You should look at this module :
https://www.npmjs.com/package/verror
Joyent quote it on his error management best pratices : https://www.joyent.com/developers/node/design/errors
At Joyent, we use the verror module to wrap errors since it's
syntactically concise. As of this writing, it doesn't quite do all of
this yet, but it will be extended to do so.
It allow you to get details on error message. And tracking the step of the error.
And also hide details to the client with wrapped error : WError() who returns only the last error message.
I answer my own question to explain what i finaly did to have the wanted encapsulation.
I used https://www.npmjs.com/package/verror as Sachacr suggested.
Then I extended it that way :
my_error.js :
var VError = require('verror');
var _ = require('lodash');
function MyError() {
var args = [];
var httpErrorCode;
var cause;
if (arguments.length > 0) {
var lastArgumentIndex = [arguments.length];
cause = manageCause(lastArgumentIndex, arguments);
httpErrorCode = manageHttpCode(lastArgumentIndex, arguments);
for (var i = 0; i < lastArgumentIndex; i++) {
args[i] = arguments[i];
}
}
this.__proto__.__proto__.constructor.apply(this, args);
if (cause) {
if (this.stack) {
this.stack += '\n' + cause.stack;
} else {
this.stack = cause.stack;
}
}
this.httpErrorCode = httpErrorCode;
}
MyError.prototype.__proto__ = VError.prototype;
function manageCause(lastArgumentIndex, arguments) {
if (lastArgumentIndex[0] > 0
&& arguments[lastArgumentIndex[0] - 1] instanceof Error) {
lastArgumentIndex[0]--;
return arguments[lastArgumentIndex[0]];
}
}
function manageHttpCode(lastArgumentIndex, arguments) {
if (lastArgumentIndex[0] > 0
&& _.isNumber(arguments[lastArgumentIndex[0] - 1])) {
lastArgumentIndex[0]--;
return arguments[lastArgumentIndex[0]];
}
}
module.exports = MyError;
It allows me to use it easily in my code :
var MyError = require('./my_error.js');
function withErrors() {
try {
// something with errors
} catch (err) {
// This is the same pattern as VError
return new MyError("My message", err, 401);
}
}
function somethingToDo(req, res) {
var result = withErrors();
if (result instanceof MyError) {
logger.warn(result);
res.status(result.httpErrorCode).send(result.message).end();
return
}
}
That way, i hace a nice stack trace with call path and every line involved in error/exception.
Hope it will help people, cause i searched a looooong time :)
EDIT : I modified my MyError class to add HTTP Error codes and clean arguments management.
You should be able to do something like:
funtion exception(message, error) {
this.message = message;
this.stacktrace = error.stack;
}
try {
if(someData == false)
throw new exception("something went wrong!", new Error());
}
catch(ex) {
console.log(ex.message);
console.log(ex.stacktrace);
}
You can then throw your own custom exception instance containing whatever debugging info you need.
EDIT: added stack trace to exception object

Monitoring chrome.storage throttle limits

I'm using chrome.storage in an extension and would like to avoid triggering runtime errors due to exceeding one of the documented throttles for either the sync or local stores. (things like QUOTA_BYTES, QUOTA_BYTES_PER_ITEM)
My first choice would be to intercept these errors prior to a runtime error being generated; alternatively I could track usage on the extension side and try to avoid triggering them.
This feels like an issue that someone must have addressed, but I can't seem to find any solutions - any suggestions appreciated.
Here's a sample of the solution I'm going with (using Angular, so there are promises in here), although having to regex the chrome.runtime.lastError value is pretty ugly IMO:
var service = {
error: function(lastError) {
if((lastError) && (lastError.message)) {
var errorString = lastError.message;
if(/QUOTA_BYTES/.test(errorString)) {
return true;
} else if(/QUOTA_BYTES_PER_ITEM/.test(errorString)) {
return true;
} else if(/MAX_ITEMS/.test(errorString)) {
return true;
} else if(/MAX_WRITE_OPERATIONS_PER_HOUR/.test(errorString)) {
return true;
} else if(/MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE/.test(errorString)) {
return true;
}
return false;
} else {
return false;
}
},
write: function(key, value) {
var deferred = $q.defer();
var data = {};
data[key] = value;
chrome.storage.sync.set(data, function() {
if(service.error(chrome.runtime.lastError)) {
deferred.reject('Write operation failed: '
+ chrome.runtime.lastError.message);
} else {
deferred.resolve();
}
});
return deferred.promise;
}
};
return service;

Resources