当前位置:网站首页>Hard core JS: there may be a memory leak in your program
Hard core JS: there may be a memory leak in your program
2022-06-24 05:04:00 【User 1250838】
Statement : This article is the Nuggets' first signing article , Reprint without authorization prohibited .
Write it at the front
I think many students see a memory leak , Two words will jump out of your heart : Closure !!! Let you say something else and you'll be silent . If your knowledge of memory leaks is limited to closures , It's really time to read this article carefully , Closures can cause memory leaks , But memory leaks aren't just closures , It's just one of the triggers of a memory leak .
The written program slowly becomes stuck and even crashes after running for a period of time ?
As the title , There may be a memory leak in your program , Speaking of memory leaks , It is recommended to read 「 hardcore JS」 Do you really understand the garbage collection mechanism One article , Then look at this article, it will be more transparent , After all, garbage collection and memory leaks are causal , The garbage is recycled. Nothing happened , Garbage is not recycled is a memory leak .
In this article, we will introduce the related concepts of memory leakage and some problems causing memory leakage , We will also focus on the troubleshooting of memory leakage 、 Positioning and repair methods ( Learn and use ), Finally, it simply expands the other two of the three major pieces of front-end memory, memory expansion and frequent GC The concept of .
What is memory leak
There is a garbage collection mechanism in the engine , It is mainly aimed at some objects that are no longer used in programs , Clean it up and recycle it to free up memory .
Then the garbage collection mechanism will put objects that are no longer used ( The garbage ) Recycle it all ?
In fact, although the engine has made various optimizations for garbage collection, so as to ensure that garbage can be recycled as much as possible , But that's not to say that we don't have to care about this at all , We should still actively avoid some garbage collection operations that are not conducive to the engine in our code , Because not all useless object memory can be recycled , When memory objects are no longer used , When not recycled in time , We call it the Memory leak (Memory leak).
Common memory leaks
The code is not standardized , Two lines of tears of colleagues , Next, let's look at some common cases that can cause memory leaks .
Improper closure
A closure is a function that is nested inside and return A function ??? This is what most people think of as a closure , ok , It is indeed , Let's take a look at some JS The description in the highlight book :
- JavaScript Advanced programming : A closure is a function that has access to variables in the scope of another function
- JavaScript Authoritative guide : From a technical point of view , be-all JavaScript Functions are all closures : They are all objects , They are all linked to the scope chain
- You don't know JavaScript: When a function can remember and access its lexical scope , There's a closure , Even if the function is executed outside the current lexical scope
As described in the above three books , Then the scope of closure is relatively wide , Let's not tangle with the definition of closure for the time being , In the simplest way 、 Let's look at the examples of closures that we all agree on :
function fn1(){
let test = 'isboyjc'
return function(){
console.log('hahaha')
}
}
let fn1Child = fn1()
fn1Child()
Is the above example a closure ? Did it cause a memory leak ?
Obviously, it is a typical closure , But it didn't cause a memory leak , Because there is no right in the returned function fn1 References inside functions , in other words , function fn1 Inside test Variables are completely recyclable , Then let's see :
function fn2(){
let test = 'isboyjc'
return function(){
console.log(test)
return test
}
}
let fn2Child = fn2
fn2Child()
Is the above example a closure ? Did it cause a memory leak ?
Closures, obviously , And because return There is a function in the function of fn2 Medium test Variable references , therefore test It's not recycled , This causes a memory leak .
So how to solve it ?
In fact, after the function call , Just leave the external reference empty , as follows :
function fn2(){
let test = 'isboyjc'
return function(){
console.log(test)
return test
}
}
let fn2Child = fn2
fn2Child()
fn2Child = null
“ Reduce the use of closures , Closures can cause memory leaks ...”
Wake up , This sentence is in the past tense , Its description is inaccurate ,So, It should be said that improper use of closures may cause memory leaks .
Implicit global variables
We know JavaScript Our garbage collection is automatic , The garbage collector will find out the data that is no longer used at regular intervals , And release the memory space it occupies .
Let's look at global variables and local variables , The local variables in the function are no longer needed after the execution of the function , So the garbage collector recognizes and releases them . But for global variables , It is difficult for the garbage collector to determine when these variables are not needed , So global variables are usually not recycled , The global variables we use are OK Of , But at the same time, we need to avoid some additional global variables , as follows :
function fn(){
// There is no declaration, which creates an implicit global variable test1
test1 = 'isboyjc1'
// Internal function this Point to window, Made implicit global variables test2
this.test2 = 'isboyjc2'
}
fn()
Call function fn , because No statement and Function this The problem caused two additional implicit global variables , These two variables will not be recycled , We should try our best to avoid this situation , In development, we can use strict patterns or through lint Check to avoid these situations , So as to reduce the memory cost .
besides , We will inevitably use global variables in our programs , These global variables cannot be recycled unless they are cancelled or reassigned , This requires our extra attention , That is, when we use global variables to store data , Make sure you leave it empty or reassign it after use , It's also very simple , Set it to... After use null that will do , Especially when using global variables as a cache that continuously stores a large amount of data , We must remember to set the storage limit and clean it up in time , Otherwise, the amount of data will be larger and larger , Memory pressure will also increase .
var test = new Array(10000) // do something test = null
free DOM quote
Consider performance or code simplicity , We do it in the code DOM Variable cache is used when DOM Reference to node , But when removing nodes , We should release cached references synchronously , Otherwise, the free subtree cannot be released .
<div id="root">
<ul id="ul">
<li></li>
<li></li>
<li id="li3"></li>
<li></li>
</ul>
</div>
<script>
let root = document.querySelector('#root')
let ul = document.querySelector('#ul')
let li3 = document.querySelector('#li3')
// because ul Variable existence , Whole ul And its child elements cannot GC
root.removeChild(ul)
// Although it is empty ul Variable , But because of li3 Variable references ul Child nodes of , therefore ul Elements still cannot be GC
ul = null
// No variable references , At this point you can GC
li3 = null
</script>
As shown above , When we use variable caching DOM Deleted node after node reference , If you don't empty the variables referenced by the cache , Still can't go on GC, There will also be a memory leak .
If we leave the parent node empty , But the child node reference of the deleted parent node is also cached in the variable , Then it will lead to the whole father DOM The entire free node tree under the node tree cannot be cleaned up , There will still be memory leaks , The solution is to leave the variables that reference the child nodes empty , Here's the picture :
The timer of forgetting
We often use timers in programs , That is to say setTimeout and setInterval, Let's start with an example :
// get data
let someResource = getData()
setInterval(() => {
const node = document.getElementById('Node')
if(node) {
node.innerHTML = JSON.stringify(someResource))
}
}, 1000)
It's my casual copy A small example of , Put the data into the code every second Node Go to the node , But in setInterval There is no end , The variables in the callback function and the callback function itself cannot be recycled .
What is the end ? Which is called clearInterval. If not clear If you drop it , Will cause memory leaks . More Than This , If the callback function is not recycled , Then the dependent variables in the callback function cannot be recycled . So in the example above ,someResource Can't be recycled .
Again ,setTiemout There will be the same problem , therefore , When you don't need interval perhaps timeout when , Better call clearInterval perhaps clearTimeout To get rid of , in addition , In the browser requestAnimationFrame There's a problem , We need to use... When we don't need it cancelAnimationFrame API To cancel the use of .
Forgotten event listener
When the event listener mounts the relevant event handler in the component , When the component is destroyed and it is not cleared actively , The variables or functions that are referenced are considered necessary and will not be recycled , If internally referenced variables store a lot of data , May cause the page to occupy too much memory , This causes an unexpected memory leak .
We take the Vue Components, for example ,React It's the same in the hotel :
<template>
<div></div>
</template>
<script>
export default {
created() {
window.addEventListener("resize", this.doSomething)
},
beforeDestroy(){
window.removeEventListener("resize", this.doSomething)
},
methods: {
doSomething() {
// do something
}
}
}
</script>
Forgotten listener mode
Listener mode must be known to all of us , Whether it's Vue 、 React Or something else , For the current front-end development framework , It is very common for listener mode to realize some message communication , such as EventBus. . .
When we implement the listener mode and mount the relevant event handling functions in the component , When the component is destroyed and it is not cleared actively , The variables or functions that are referenced are considered necessary and will not be recycled , If internally referenced variables store a lot of data , May cause the page to occupy too much memory , This can also cause unexpected memory leaks .
Or use it Vue Component examples , Because it's easier :
<template>
<div></div>
</template>
<script>
export default {
created() {
eventBus.on("test", this.doSomething)
},
beforeDestroy(){
eventBus.off("test", this.doSomething)
},
methods: {
doSomething() {
// do something
}
}
}
</script>
Above , We just need to beforeDestroy Just clear the component in its destruction life cycle .
Forgotten Map、Set object
When using Map or Set When storing objects , Same as Object Consistency is a strong reference , If you do not actively clear the reference , It also causes memory not to be recycled automatically .
If you use Map , In the case of keys as objects , May adopt WeakMap,WeakMap Objects are also used to hold key value pairs , For keys are weak references ( notes :WeakMap Only for keys that are weak references ), And must be an object , And the value can be any object or original value , Because it is a weak reference to the object , Will not interfere with Js The garbage collection of .
If needed Set Reference object , May adopt WeakSet,WeakSet Object allows you to store unique values for weak references to objects ,WeakSet The values in the object are also not repeated , And only weak references to objects can be saved , Also due to weak references to objects , Will not interfere with Js The garbage collection of .
Here may need a brief introduction , On weak references , Let's start with strong references , Before we said JS Our garbage collection mechanism is if we hold a reference to an object , Then the object will not be garbage collected , Here's the quote , Refers to Strong citation , A weak reference is an object that is only referenced by a weak reference , Is considered inaccessible ( Or weakly accessible ) Of , So it can be recycled at any time .
Don't understand ? Just look at the example :
// obj Is a strong reference , Objects are stored in memory , You can use
let obj = {id: 1}
// rewrite obj quote
obj = null
// Object removed from memory , Recycling {id: 1} object
The above is a simple method to clear object references by overriding references , Make it recyclable .
Look at the following one :
let obj = {id: 1}
let user = {info: obj}
let set = new Set([obj])
let map = new Map([[obj, 'hahaha']])
// rewrite obj
obj = null
console.log(user.info) // {id: 1}
console.log(set)
console.log(map)
In this example, we rewrite obj in the future ,{id: 1} Will still exist in memory , because user Object and the following set/map All strongly quote it ,Set/Map、 object 、 Array objects are strong references , So we can still get {id: 1} , If we want to clear, we can only rewrite all references and empty them .
Now let's see WeakMap as well as WeakSet:
let obj = {id: 1}
let weakSet = new WeakSet([obj])
let weakMap = new WeakMap([[obj, 'hahaha']])
// rewrite obj quote
obj = null
// {id: 1} It will be next time GC Delete from memory
As shown above , Used WeakMap as well as WeakSet Weak references , take obj Quote set to null after , object {id: 1} It will be next time GC The memory is cleaned out .
Uncleaned Console Output
In the process of writing code , There is no way to avoid some output , In some small teams, the project may go online without cleaning up these console, I don't know these console It's also a hidden danger , At the same time, it is easy to be ignored , The reason why we can see the data output on the console , Because the browser saves the information and data references of our output objects , This is why it also causes memory leaks .
therefore , In the development environment, we can use the console output to facilitate our debugging , But in the production environment , Be sure to clean up the output in time .
Memory leak troubleshooting 、 Location and repair
As I said at the beginning , After running the program for a period of time, it slowly becomes stuck and even crashes , I don't know why , Let's go through the troubleshooting through an example 、 The whole process of locating and repairing memory leaks , On the blackboard , This is what you can really use .
Since we have mentioned several cases that will cause memory leakage , Let's use these cases to write Demo To check whether there is memory leakage from the perspective of the browser , Locate the source of the leak and repair it if it exists .
First , Let's make up an example of a memory leak :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<button id="click">click</button>
<h1 id="content"></h1>
<script>
let click = document.querySelector("#click");
let content = document.querySelector("#content")
let arr = []
function closures() {
let test = new Array(1000).fill('isboyjc')
return function () {
return test
}
}
click.addEventListener("click", function () {
arr.push(closures())
arr.push(closures())
content.innerHTML = arr.length
});
</script>
</body>
</html>
As shown above , This is a very simple example of a memory leak consisting of improper use of closures .
Let's briefly introduce , Just look at script Medium JS The code can be , First , We have a closures function , This is a closure function , The simplest closure function must not be introduced to you , And then we'll create a page for button Element is bound to a click event , Every click will execute 2 Close the function twice and execute the result push To the global array arr in , Because the execution result of the closure function is also a function, and there is an internal array of the original closure function test References to , therefore arr Each element in the array makes its reference inside the closure test Array objects cannot be recycled ,arr How many elements does an array have , That means how many times we have closure references , So the more clicks this program has ,push The more , The more memory consumption , The page will become more and more blocked .
That's for later observation , In the program, we click the button every time , Global array arr The length data of is updated on the page , From 0 Start , Every click , Page value plus 2.
Of course , This is an example written by ourselves , As God, we know what causes , Now, now , Forget this , Suppose this is one of our project programs , Development is completed and delivered to test , The little sister found that after clicking the button in the program, the page became more and more dull , Then I mentioned it BUG.
As programmers, we must be :“ Just refresh the page , Refresh when you get stuck !!!”
Um. ... Products and tests will definitely not agree , Let's change the sentence of "customer first" ..
All right , Then change it , The first step is to find out what went wrong 、 What caused , Let's call this link the problem investigation stage .
Troubleshoot problems
Chrome The developer's tool is what we call the browser console (Chrome Devtool ) In fact, it is very powerful , It can help us analyze the performance of programs like 、 Security 、 Internet and other things , It also allows us to quickly locate the source of the problem , It's just that most people are not familiar with its use .
Because of this article, we focus on memory leakage , Then we will default that the above program has checked all items except memory and there is no problem , Next, check the memory .
First, we turn on the browser's traceless mode , Then open the web page program code to check , Then open the console , The whole program interface is very simple , Here's the picture :
And then we found Performance This panel , Formerly called Timeline , It is Chrome Devtool A sharp tool for monitoring performance indicators , It can record and analyze all kinds of events that occur in the life cycle of the website , We can use it to monitor and analyze various performance conditions in our program , This includes memory , Here's the picture :
Next, let's start , Be sure to check... Before you start Memory The option is marked in the figure above 5 , So we can see the memory related analysis .
Click start recording ( Mark 1) Enter the recording state , Then clean up GC, That is, click on the small trash can ( Mark 6).
Then crazy click on the page click Button 100 Time , At this time, the value on the page should be 200, Let's click on the little trash can again , Manual trigger once GC.
Click on the page crazily again click Button 100 Time , At this time, the value on the page should be 400, Then stop recording .
Let's look at the data panel generated by the console , Here's the picture :
Two pieces with red circles on them , That is to say Heap The corresponding part indicates that the memory is falling back periodically , Simply put, our memory situation .
We can see clearly , Memory data shows a rising trend , Some people may say whether it has not been implemented in this period of time GC Well ? Don't worry. , Remember when we were 200 Did you click on the small trash can when you were , That is, we manually trigger garbage collection once , We can find out from the page snapshot above that when the page value is 200 Where was the moment of , It's simple , Just move the mouse over the memory snapshot , Here's the picture :
You can see , Even if we do a garbage collection operation manually , But the memory after cleaning is not reduced much , We infer from this , There may be a memory leak in the click operation of this program .
OK, I found the problem , Then the next step is to locate the source of the leak .
You might say , Now that the problem has been found, it is the click event , Just go and change it ?
Need to know , This is a simple example we wrote , We can see the problem at once , But in a real project, there may be a lot of operations in a click event , All we know is that the click event may cause a memory leak , But I don't know which step of the click event is the specific problem , We don't know the cause and location of more fine-grained , These still need our further analysis to locate .
Analyze positioning
Next, we start to analyze and locate the source of leakage
Chrome Devtool It also provides us with Memory panel , It can provide us with more details , Like records JS CPU Execution time details 、 Show JS Objects and related DOM Memory consumption of nodes 、 Record the details of memory allocation, etc .
Among them Heap Profiling Can record the current heap memory heap Snapshot , And generate the description file of the object , The description document gives the current JS All the objects used to run , And the amount of memory these objects occupy 、 The hierarchy of references and so on , It can be used to locate the specific cause and location of the problem .
Be careful , Is not Performance The one under the panel Memory , But with Performance The same level of the panel Memory panel , Here's the picture :
Now the page value is 400, Of course, you can also refresh the page from 0 Start , Here we choose to continue
First click on the small trash can ( Mark 3), Trigger GC, Get rid of useless things from memory
Click start to generate snapshot ( Mark 1), Generate the first snapshot and select , Here's the picture :
Briefly introduce the meaning of the small picture above :
In the list on the left Snapshot 1 Represents the snapshot we generated 1, That is, the memory state at that moment
Choose Snapshot 1 Then there is the right view table , There is a drop-down box at the top left of the table , It has four values
- Summary: Group by constructor , Capture the object and its memory usage , Can be understood as a memory summary , For tracking and positioning DOM Memory leak of node
- Comparison: Compare the memory snapshots before and after an operation , Analyze the memory release before and after the operation , It is convenient to confirm whether there is a memory leak and the cause
- Containment: The specific content of the probe stack , Provide a view to see the object structure , Help analyze object references , Analyzable closures and deeper object analysis
- Statistics: Statistical view
The drop-down will select... For us by default Summary , So the table below shows a snapshot 1 Memory summary of data in , A simple understanding is a snapshot 1 The moment of generation , What is stored in memory , Including information occupying memory and so on .
Let's have a brief understanding of Summary What do the columns of the option data table represent
- Constructor: Show all constructors , Click on each constructor to see all the objects created by that constructor
- Distance: Displays the distance from the shortest node path to the root node , Reference level
- Shallow Size: Displays the memory occupied by the object , Memory occupied by other objects that do not contain internal references
- Retained Size: Displays the total memory occupied by the object , Memory occupied by other objects containing internal references
OK, Just know so much for the time being , Let's move on , First click on the small trash can to manually execute once GC, And then click 1 Next page click Button , Finally, click the generate snapshot button again , Generate our second snapshot .
For accuracy , Let's do it a few more times , as follows :
First click on the small trash can to manually execute once GC, And then click 2 Next page click Button , Finally, click the generate snapshot button again , Generate our third snapshot
First click on the small trash can to manually execute once GC, And then click 3 Next page click Button , Finally, click the generate snapshot button again , Generate our fourth snapshot
And then , We selected the snapshot 2, And change the drop-down box above it from the default Summary The option switches to comparison Options , That is to compare the memory difference between the current snapshot and the previous snapshot , Here's the picture :
Let's look at the options Comparison Drop it down , What does the table column below represent , Here are some important
- New: How many new objects
- Deleted: How many objects have been recycled
- Delta: Number of new objects subtract Number of objects recycled
EH , We'll smell a little like that here , We need to focus on Delta , As long as it is positive, there may be problems , The intimate console has arranged the order for us , Let's look at the top several in turn .
Of course , We also need to know what each row of data represents , Turn your attention to Constructor This column , We talked about that , This column is a constructor , Each constructor click can view all the objects created by the constructor , Let's first introduce what the common constructors in this column roughly represent
- system、system/Context Represents some references created by the engine itself and by the context , Don't pay too much attention to these , Is not important
- closure Represents the object reference in some function closures
- array、string、number、regexp This series also shows , It refers to the array 、 character string 、 The object type of a number or regular expression
- HTMLDivElement、HTMLAnchorElement、DocumentFragment Wait, these are actually the references or specified elements in your code DOM Object reference
EH , Much clearer , Then we can compare them in turn 1->2 / 2->3 / 3->4 Let's see what's wrong .
take it easy , Think about what we're going to do now ? You need to click a snapshot separately and then select comparison , And then look Delta The items listed as positive numbers are analyzed again , Such operations need to be 3 Time , Because we have 4 A snapshot , Need comparative analysis 3 Time , Sometimes even more snapshots may be generated to ensure accuracy .
Is there an easier way ? yes , we have , We can directly select the snapshot to be compared , There is also a pop-up box on the right table. We can directly select snapshots for comparison , And it will filter out some useless information for us :
Let's do the actual operation , Select snapshot on the left 2, choice snapshot 1 And snapshot 2 Make a comparative analysis , give the result as follows :
You can see , In the list, only the comparison filtered 4 Item differences
system/Context We don't need to care about .
closure As mentioned above, it represents closure reference , Let's click this item to see the specific information :
You can see , closure There are two references below , It also points out to us that in the code 21 That's ok , Click to select one of the references , More detailed information is shown below .
Why are there two references after expansion ? Remember when we were generating snapshot 2 The operation of , Manually performed once GC And clicked once click Button , Triggered a click event , In the click event, we execute and push The closure function twice , So is 2 Bar record .
Finally, let's see array , The existence of array references here is entirely due to the global array variable in our case code arr The existence of , After all, every click push Data? , This is why we should pay extra attention to the use of global variables mentioned above 、 Clean it up in time or something , This is because if you don't clean up in this case, these global variables will be in memory until the page is closed , Maybe you have some questions about the constructor column 2 Items are all arrays. There is a question , There's nothing wrong with it , One represents arr In itself , One represents the array variable referenced inside the closure test ( If you forget, review the above case code ), This can also be achieved through Distance The reference level represented in the column GET, One level is 7, One level is 8. As for the location of the code leaked by the array, we can also click to expand and select its reference entry , You can see the code location in the details , The same operation as the closure above , I'm not going to do that here .
EH , That seems to know the specific source of the leak , Let's confirm again , Select snapshot on the left 4, choice snapshot 3 And snapshot 4 Make a comparative analysis , snapshot 4 The operation we did before was performed manually GC And clicked three times click Button , If the above conclusion is correct , It should be with us snapshot 1 and snapshot 2 The data items of the comparison results are consistent 4 term , But the internal reference of each item will be 6 strip , Because we clicked the button three times before this snapshot , Execute and push The closure function twice , Look at the results :
image-20210707041841176
Um. , Everything seems to be clear here , There are altogether 2 individual , One is code 21 The closure of the row refers to the memory leak caused by the array , Second, global variables arr Memory leaks caused by the increasing number of elements .
Analysis and positioning succeeded , Go to the next step , Fix and verify again .
Repair verification
Because this is a case written temporarily , There is no specific scene , Therefore, there is no way to use targeted methods to repair ,So, This step temporarily ignores , But in the project, we still have to solve .
For example, the problem that the global object keeps growing , Global objects we cannot avoid , But you can limit the size of global objects , According to the scene, you can clean up a part beyond .
For example, the problem of closure reference , Don't let it reference , Or empty after execution , This is all mentioned above .
All in all , Everything needs to choose the solution according to the specific scenario , After solving the problem, repeat the above troubleshooting process to see the memory .
Three major pieces of memory
In fact, there are three main problems about memory in the front end , I affectionately call them the three big pieces of memory :
Memory leak We've been talking for a long time , The object is no longer in use but has not been recycled , Memory not freed , Memory leak , If you want to avoid it, avoid making useless data still have reference relationships , That is, pay more attention to several common memory leaks mentioned above .
Memory expansion That is, in a short period of time, the memory occupation rises rapidly and reaches a peak , To avoid the need to use technical means to reduce the occupation of memory .
frequent GC Same name , Namely GC It is carried out very frequently , Generally, the frequent use of large temporary variables leads to the rapid filling of the Cenozoic space , And every time the Cenozoic is full, it triggers GC, frequent GC It will also cause the page to get stuck , If you want to avoid it, don't make too many temporary variables , Because temporary variables will be recycled if they are not used , This is similar to what we said in memory leak to avoid using global variables , Actually , Just grasp the degree , Not too much, just OK.
Last
If your program is stuck but you can't find the reason , Then try the troubleshooting method of this article , Maybe it's caused by a memory leak , meanwhile , It is also a point we need to pay extra attention to when doing page optimization .
That's it today , you GET Have we arrived ? Welcome to make mistakes ! Writing is not easy to , Use your little hand to praise , Collecting and eating ash is a big taboo
You are welcome to pay attention to 「 hardcore JS」 special column , An in-depth introduction to JS Little knowledge , Let you know what you don't know JavaScript!!!
边栏推荐
- Find the current index of gbase 8C database?
- cuDNN installation
- RedHat 8 time synchronization and time zone modification
- Introduction to gradient descent method - black horse programmer machine learning handout
- Problem: SQL create stored procedure
- What's wrong with the failure of uploading web pages to ECS? How many kinds of servers are there
- What domain name does not need to be filed? What should be done for domain name filing
- Introduction to the "penetration foundation" cobalt strike Foundation_ Cobalt strike linkage msfconsole
- Facebook internal announcement: instant messaging will be re integrated
- Bi-sql insert into
猜你喜欢

Leetcode (question 1) - sum of two numbers

What are the disadvantages of the free IP address replacement tool?

CTF learning notes 18:iwesec file upload vulnerability-03-content-type filtering bypass

Training methods after the reform of children's programming course

SAP mts/ato/mto/eto topic 10: ETO mode q+ empty mode unvalued inventory policy customization

『渗透基础』Cobalt Strike基础使用入门_Cobalt Strike联动msfconsole

Introduction to the "penetration foundation" cobalt strike Foundation_ Cobalt strike linkage msfconsole

Detailed explanation of tcpip protocol

Facebook internal announcement: instant messaging will be re integrated

重新认识WorkPlus,不止IM即时通讯,是企业移动应用管理专家
随机推荐
Problem: SQL create stored procedure
Where is the cheaper domain name? What should I pay attention to when buying a domain name?
Automatically convert local pictures to network pictures when writing articles
What is the secondary domain name of the website? What is the relationship between the secondary domain name and the primary domain name?
Detailed explanation of the process after the browser enters the domain name and web address
Disaster recovery series (IV) - disaster recovery construction of business application layer
Integration of Alibaba cloud SMS services and reasons for illegal message signing
让孩子们学习Steam 教育的应用精髓
What is required for domain name filing and how to select an enterprise domain name
The conference assistant hidden in wechat is the best way to work efficiently!
What is the difference between a traditional data center and a cloud computing data center?
Introduction to vulnerability priority technology (VPT)
MySQL cases MySQL find out who holds the row lock (RC)
How do ECS create FTP accounts? What should I pay attention to during creation?
How to file ECS? What should be paid attention to when selecting ECS
"Emergency response practice" logparser log analysis practice
Digital transformation practice of Zheshang Bank
Inventory of common tools used by dry goods | data journalists
Powerbi - for you who are learning
Where to buy domain name space? Can the domain name be repeated?