Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: Add Automatic Free Block #63671

Closed
qiulaidongfeng opened this issue Oct 22, 2023 · 16 comments
Closed

proposal: Go 2: Add Automatic Free Block #63671

qiulaidongfeng opened this issue Oct 22, 2023 · 16 comments
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Milestone

Comments

@qiulaidongfeng
Copy link
Member

qiulaidongfeng commented Oct 22, 2023

Author background

  • Would you consider yourself a novice, intermediate, or experienced Go programmer?
    Experienced Go Programmer
  • What other languages do you have experience with?
    C.

Related proposals

  • Has this idea, or one like it, been proposed before?
    • If so, how does this proposal differ?
      I don't know.
  • Does this affect error handling?
    • If so, how does this differ from previous error handling proposals?
      no.
  • Is this about generics?
    • If so, how does this relate to the accepted design and other generics proposals?
      no.

Proposal

  • What is the proposed change?

Add automatic Free blocks to go language.

  • Who does this proposal help, and why?
    People who require zero GC or do not have STW.
  • Please describe as precisely as possible the change to the language.

The syntax is:

AutoFree N {
//any stmt
}

N is the number of memory bytes that the memory pool is prepared to wait for Alloc.

Semantic refers to the memory allocated on the heap, which will automatically be free after the end of the block.

  • What would change in the language spec?
    I don't quite understand how to write the Go language specification for EBNF.
  • Please also describe the change informally, as in a class teaching Go.

By using automatic Free blocks, heap allocation within the block can be automatically released after the block ends.

N is the number of bytes waiting for Alloc to be pre allocated by the memory pool.

When all heap allocations are in the automatic Free block, GOGC=0 can be used to turn off GC to avoid STW
The syntax is:

AutoFree N {
// any stmt
}
  • Is this change backward compatible?
    no.
    • Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
      Show example code before and after the change.

    • Before
      GC is required.

    • After
      GC can be turned off because heap allocation can be automatically released.

  • Orthogonality: how does this change interact or overlap with existing features?
    I don't know.
  • Is the goal of this change a performance improvement?
    yes.
    • If so, what quantifiable improvement should we expect?
      Can eliminate the need for GC, STW disappears.
    • How would we measure it?
      I don't know.

Costs

  • Would this change make Go easier or harder to learn, and why?
    It's even harder because of the new features.
  • What is the cost of this proposal? (Every language change has a cost).
    I don't know.
  • How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
    I don't know.
  • What is the compile time cost?
    I don't know.
  • What is the run time cost?
    I don't know.
  • Can you describe a possible implementation?

AutoFree N {is rewritten to create a memory pool,} is rewritten to free memory in the memory pool, and the heap allocation between {and} is allocated in the memory pool.

  • Do you have a prototype? (This is not required.)
    There is no prototype for GO, there are prototypes in other languages, but the document is not written in English.
@qiulaidongfeng qiulaidongfeng added LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change labels Oct 22, 2023
@gopherbot gopherbot added this to the Proposal milestone Oct 22, 2023
@chad-bekmezian-snap
Copy link

Unless I'm missing something, this is backwards compatible. We're adding a feature that makes it possible to avoid GC. The previous GC functionality would still be available though.

@rittneje
Copy link

  1. What happens if the block needs to use more heap memory than N? Does the program just crash?
  2. What happens if a heap-allocated value within the block escapes? Does it get collected anyway, leading to use-after-free bugs?
  3. What happens with goroutines that get created within the block?

@qiulaidongfeng
Copy link
Member Author

qiulaidongfeng commented Oct 22, 2023 via email

@qiulaidongfeng
Copy link
Member Author

  1. What happens if the block needs to use more heap memory than N? Does the program just crash?
  2. What happens if a heap-allocated value within the block escapes? Does it get collected anyway, leading to use-after-free bugs?
  3. What happens with goroutines that get created within the block?
  1. If the block needs to use more heap memory than N, the memory pool should automatically expand, just like append does for slicing.
  2. As soon as the AutoFree block ends, the heap allocation inside should be immediately Free. Only when pointers within a block survive outside the block can use-after-free occur.
  3. Creating goroutine in AutoFree blocks has the same semantics.

@rittneje
Copy link

As soon as the AutoFree block ends, the heap allocation inside should be immediately Free. Only when pointers within a block survive outside the block can use-after-free occur.

Yeah so you are introducing a dangerous class of bugs that doesn't exist in Go today (excluding cgo and such).

Creating goroutine in AutoFree blocks has the same semantics.

There's no synchronization. You are just going to randomly release the goroutine's heap memory in the middle of its execution?

The short of it is that this proposal seems incompatible with every library that exists, both standard and third-party. It would be so limiting that I cannot see how this feature could possibly provide any value.

@qiulaidongfeng
Copy link
Member Author

qiulaidongfeng commented Oct 22, 2023 via email

@rittneje
Copy link

But I admit that this is not as safe as GC, because the programmer may write the wrong location of the AutoFree block.

Again, the problem here is that if you call some library function, you would have to deeply inspect its code (and the code of its transitive dependencies) to draw any conclusion about when it is safe to free the memory. And you would have to repeat this exhaustive exercise any time you upgrade anything.

In the meantime, I suggest you look at the arenas experiment (emphasis on experiment!) described in #51317, which seems similar to what you've proposed, but with more safety nets.

@qiulaidongfeng
Copy link
Member Author

qiulaidongfeng commented Oct 22, 2023 via email

@randall77
Copy link
Contributor

Adding any API that could introduce a silent use-after-free bug is a non-starter.

The arena package is explicitly designed to ensure that it is not silent about use-after-free bugs. And even then, we're not sure we want to go down that road by promoting it to non-experimental.

I have already read proposal #51317 and it requires manual New and Free.

It requires New and Free of the arena, not of each individual object. New is like your AutoFree N { and Free is like the trailing `}'.

@qiulaidongfeng
Copy link
Member Author

A guess, can the Go compiler detect saving intra block pointers outside the block and reporting errors?

Perhaps by using a memory pool similar to arena, but with concurrency security. Is this proposal as safe as Arena?

It requires New and Free of the arena, not of
each individual object. New is like your
AutoFree N { and Free is like the trailing `}'.

What I mean is that Arena's New manually allocates one go object each time, and then manually calls Free only once to release all allocated go objects.

The N of this proposed AutoFree is different from Arena's New, as N is only the number of bytes that the memory pool is ready to wait for Alloc.

@findleyr
Copy link
Contributor

findleyr commented Nov 1, 2023

Per @randall77's comment, this is a non-starter. Therefore, this is a likely decline. Leaving open for four weeks for final comments.

@black23eep
Copy link

This is a good idea, but there may be some issues with the grammar design

@qiulaidongfeng
Copy link
Member Author

qiulaidongfeng commented Nov 9, 2023 via email

@qiulaidongfeng
Copy link
Member Author

Adding any API that could introduce a silent use-after-free bug is a non-starter.

The arena package is explicitly designed to ensure that it is not silent about use-after-free bugs. And even then, we're not sure we want to go down that road by promoting it to non-experimental.

I've thought of an implementation that won't be silent about use-after-free bugs!
Do something with goroutine's g.
Add memPool and localArena fields to g.
The AutoFree statement sets the memPool field and prepares N bytes for allocation, and sets the localArena field for heap allocation within the AutoFree block.
The child goroutine opened by the go statement in the AutoFree block inherits the memPool field and localArena field of the parent goroutine.
Heap allocation within the AutoFree block uses g's localArena field.
If the localArena field requires memory, obtain it from the memPool field.
After the AutoFree block ends, the memory held by the memPool field is released.
After the AutoFree block ends, if heap allocation from the in-block launched goroutine is found, or if use-after-free bugs are found, the program should react in the same way that arena packages are handled.

@X-Witf
Copy link

X-Witf commented Nov 16, 2023

Maybe you don't need to add any keywords
for example:

func one(args) result{
 //any code
 return result
 // auto free after the end
 //do not free args and result 
}

for example:

func one(){
  let arg;
  result:=two(arg)
  //auto free arg and result after the end
}
func two(arg) result{
  return result
}

@adonovan
Copy link
Member

adonovan commented Dec 6, 2023

No change in consensus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

9 participants