Learn JScript Bugs and Memory Management from me_javascript skills
1. JScript Bug
IE's ECMAScript implementation of JScript seriously confuses named function expressions, causing many people to oppose named function expressions, and even the version that is still in use (version 5.8 used in IE8) still exists The following questions.
Let’s take a look at what mistakes IE made in its implementation. As the saying goes, only by knowing the enemy can you be invincible. Let’s take a look at the following examples:
Example 1: Identifier of function expression leaked to outer scope
var f = function g(){}; typeof g; // "function"
We said earlier that the identifier of a named function expression is invalid in the external scope, but JScript obviously violates this specification. The identifier g in the above example is parsed into a function object, which is messy. Yes, many hard-to-find bugs are caused by this reason.
Note: This problem seems to have been fixed in IE9
Example 2: Treat a named function expression as both a function declaration and a function expression
typeof g; // "function" var f = function g(){};
In the feature environment, function declarations will be parsed before any expression. The above example shows that JScript actually treats the named function expression as a function declaration because it parses g before the actual declaration.
This example leads to the next one.
Example 3: Named function expressions create two completely different function objects!
var f = function g(){}; f === g; // false f.expando = 'foo'; g.expando; // undefined
Seeing this, everyone will think that the problem is serious, because modifying any object will not change the other one. This is too evil. Through this example, we can find that creating two different objects, that is to say, if you want to modify the attribute of f to save certain information, and then use it as a matter of course by referencing the same name attribute of g of the same object, then there will be a big problem. Because it's simply impossible.
Let’s look at a slightly more complicated example:
Example 4: Only parse function declarations sequentially and ignore conditional statement blocks
var f = function g() { return 1; }; if (false) { f = function g(){ return 2; }; } g(); // 2
This bug is much harder to find, but the cause of the bug is very simple. First, g is parsed as a function declaration. Since function declarations in JScript are not subject to conditional code blocks, in this nasty if branch, g is treated as another function function g(){ return 2 }, also It was just declared again. Then, all "regular" expressions are evaluated, and f is given a reference to another newly created object. Since the abominable if branch "" will never be entered when the expression is evaluated, f will continue to refer to the first function function g(){ return 1 }. After analyzing this, the problem is very clear: if If you are not careful enough and call g in f, an irrelevant g function object will be called
.You may ask, what are the differences when comparing different objects with arguments.callee? Let’s take a look:
var f = function g(){ return [ arguments.callee == f, arguments.callee == g ]; }; f(); // [true, false] g(); // [false, true]
As you can see, the reference of arguments.callee is always the called function. In fact, this is also a good thing, as will be explained later.
Another interesting example is using a named function expression in an assignment statement that does not contain a declaration:
(function(){ f = function f(){}; })();
According to the code analysis, we originally wanted to create a global attribute f (be careful not to confuse it with the general anonymous function, which uses a named declaration). JScript made a mess here. First, it changed the expression The expression is parsed as a function declaration, so f on the left is declared as a local variable (the same as the declaration in a general anonymous function). Then when the function is executed, f is already defined, and the function f() on the right {} is directly assigned to the local variable f, so f is not a global attribute at all.
After understanding how abnormal JScript is, we must prevent these problems in time. First, prevent identifiers from leaking into external scopes. Secondly, identifiers used as function names should never be quoted; remember the one in the previous example The annoying identifier g? ——If we can pretend that g does not exist, how much unnecessary trouble can be avoided. Therefore, the key is to always refer to functions via f or arguments.callee. If you use named function expressions, you should only use that name when debugging. Finally, remember to clean up functions that were created incorrectly during the declaration of a named function expression.
2. JScript memory management
After knowing these non-standard code parsing bugs, if we use it, we will find that there is actually a problem with memory. Let’s look at an example:
var f = (function(){ if (true) { return function g(){}; } return function g(){}; })();
我们知道,这个匿名函数调用返回的函数(带有标识符g的函数),然后赋值给了外部的f。我们也知道,命名函数表达式会导致产生多余的函数对象,而该对象与返回的函数对象不是一回事。所以这个多余的g函数就死在了返回函数的闭包中了,因此内存问题就出现了。这是因为if语句内部的函数与g是在同一个作用域中被声明的。这种情况下 ,除非我们显式断开对g函数的引用,否则它一直占着内存不放。
var f = (function(){ var f, g; if (true) { f = function g(){}; } else { f = function g(){}; } // 设置g为null以后它就不会再占内存了 g = null; return f; })();
通过设置g为null,垃圾回收器就把g引用的那个隐式函数给回收掉了,为了验证我们的代码,我们来做一些测试,以确保我们的内存被回收了。
测试
测试很简单,就是命名函数表达式创建10000个函数,然后把它们保存在一个数组中。等一会儿以后再看这些函数到底占用了多少内存。然后,再断开这些引用并重复这一过程。下面是测试代码:
function createFn(){ return (function(){ var f; if (true) { f = function F(){ return 'standard'; }; } else if (false) { f = function F(){ return 'alternative'; }; } else { f = function F(){ return 'fallback'; }; } // var F = null; return f; })(); } var arr = [ ]; for (var i=0; i < 10000; i++) { arr[i] = createFn(); }
通过运行在Windows XP SP2中的任务管理器可以看到如下结果:
IE7: without `null`: 7.6K -> 20.3K with `null`: 7.6K -> 18K IE8: without `null`: 14K -> 29.7K with `null`: 14K -> 27K
如我们所料,显示断开引用可以释放内存,但是释放的内存不是很多,10000个函数对象才释放大约3M的内存,这对一些小型脚本不算什么,但对于大型程序,或者长时间运行在低内存的设备里的时候,这是非常有必要的。
以上就是关于JScript的Bug与内存管理的全部介绍,希望对大家的学习有所帮助。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

As Apple's WWDC conference 2024 came to a successful conclusion, not only macos15 was announced, but the update of Apple's new iOS18 system attracted the most attention. Although there are many new features, as the first version of Apple's iOS18, people inevitably wonder whether it is necessary to upgrade Apple. iOS18, what kind of bugs are there in the latest release of Apple iOS18? After real use evaluation, the following is a summary of Apple iOS18 bugs, let’s take a look. Currently, many iPhone users are rushing to upgrade to iOS18. However, various system bugs are making people uncomfortable. Some bloggers said that you should be cautious when upgrading to iOS18 because "there are so many bugs." The blogger said that if your iPhone is

C++ object layout and memory alignment optimize memory usage efficiency: Object layout: data members are stored in the order of declaration, optimizing space utilization. Memory alignment: Data is aligned in memory to improve access speed. The alignas keyword specifies custom alignment, such as a 64-byte aligned CacheLine structure, to improve cache line access efficiency.

Best practices for C++ function memory allocation and destruction include: using local variables for static memory allocation. Use smart pointers for dynamic memory allocation. Memory is allocated in the constructor and destroyed in the destructor. Use custom memory managers for complex memory scenarios. Use exception handling to clean up resources and ensure that allocated memory is released when exceptions occur.

Custom memory allocators in C++ allow developers to adjust memory allocation behavior according to needs. Creating a custom allocator requires inheriting std::allocator and rewriting the allocate() and deallocate() functions. Practical examples include: improving performance, optimizing memory usage, and implementing specific behaviors. When using it, you need to pay attention to avoid freeing memory, manage memory alignment, and perform benchmark tests.

In a multi-threaded environment, C++ memory management faces the following challenges: data races, deadlocks, and memory leaks. Countermeasures include: 1. Use synchronization mechanisms, such as mutexes and atomic variables; 2. Use lock-free data structures; 3. Use smart pointers; 4. (Optional) implement garbage collection.

C++ function memory management provides extensions and advanced technologies, including: Custom allocator: allows users to define their own memory allocation strategies. placementnew and placementdelete: used when objects need to be allocated to specific memory locations. Advanced technologies: memory pools, smart pointers, and RAII to reduce memory leaks, improve performance, and simplify code.

Memory for functions in Go is passed by value and does not affect the original variable. Goroutine shares memory, and its allocated memory will not be reclaimed by GC until Goroutine completes execution. Memory leaks can occur by holding a completed Goroutine reference, using global variables, or avoiding static variables. To avoid leaks, it is recommended to cancel Goroutines through channels, avoid static variables, and use defer statements to release resources.

The reference counting mechanism is used in C++ memory management to track object references and automatically release unused memory. This technology maintains a reference counter for each object, and the counter increases and decreases when references are added or removed. When the counter drops to 0, the object is released without manual management. However, circular references can cause memory leaks, and maintaining reference counters increases overhead.
