September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Laeeth Isharc | On Tuesday, September 13, 2016 17:48:38 Laeeth Isharc via Digitalmars-d wrote:
> On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh
>
> wrote:
> > On 13/09/16 02:21, deadalnix wrote:
> >> I stay convinced that an hybrid approach is inevitable and am
> >> surprised
> >> why few are going there (hello PHP, here right).
> >
> > Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory.
> >
> > Shachar
>
> Hi Shachar.
>
> I hope you're well.
>
> Would you mind elaborating a bit on why the cost of GC managed memory is as high as you imply when combined with other approaches, at least on a 64 bit machine and presuming you have a degree of hygiene and don't directly use a pointer allowed to point to either. Eg if you use GC for long lived allocations and RC for short lived ones (and the RC constructor makes sure the thing is not registered with the GC so that takes care of short lived parts of long lived structures), how in practice would this be a problem ? I am no GC expert, but keen to update my mental model.
As I understand it, the problem is that the length of time that the GC scan takes - and therefore that the world is stopped - depends on how much memory it has to scan, not on how much memory has been allocated by the GC. In many cases, that's just the GC heap plus the stack, but if you're malloc-ing memory, and that memory can hold references to GC-allocated memory, then you have to tell the GC to scan that memory too in order to avoid having anything it references being prematurely collected. So, ultimately, how expensive the GC is in terms of performance generally depends on how much memory can hold referencs to GC-allocated objects and not how many such objects there are, meaning that avoiding allocating with the GC in a lot of your code doesn't necessarily save you from the performance cost of the GC. To avoid that cost, you'd need to either not have many places in malloc-ed memory which could refer to GC-allocated memory, or you'd need to write your code in a way that the it was guaranteed that the GC-allocated objects that were referenced in malloc-ed memory would have other references in memory that was scanned that lived longer htan the malloc-ed memory so that the malloc-ed memory wouldn't need to be scanned (which is quite possible in some circumstances but potentially risky).
Using a 64-bit system significantly reduces the risk of false pointers, but it doesn't reduce the amount of memory that actually needs to be scanned. And whether using the GC for long-lived allocations and RC for short-lived ones would help would depend primarily on how many such objects would be around at any one time - and of course, whether they refer to GC-allocated memory and would thus need to be scanned. But reducing the amount of memory that the GC needs to scan and reduce how much is GC-allocated are two separate - albeit related - problems.
- Jonathan M Davis
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis wrote:
> On Tuesday, September 13, 2016 17:48:38 Laeeth Isharc via Digitalmars-d wrote:
>> On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh
>>
>> wrote:
>> > On 13/09/16 02:21, deadalnix wrote:
>> >> I stay convinced that an hybrid approach is inevitable and am
>> >> surprised
>> >> why few are going there (hello PHP, here right).
>> >
>> > Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory.
>> >
>> > Shachar
>>
>> Hi Shachar.
>>
>> I hope you're well.
>>
>> Would you mind elaborating a bit on why the cost of GC managed memory is as high as you imply when combined with other approaches, at least on a 64 bit machine and presuming you have a degree of hygiene and don't directly use a pointer allowed to point to either. Eg if you use GC for long lived allocations and RC for short lived ones (and the RC constructor makes sure the thing is not registered with the GC so that takes care of short lived parts of long lived structures), how in practice would this be a problem ? I am no GC expert, but keen to update my mental model.
>
> As I understand it, the problem is that the length of time that the GC scan takes - and therefore that the world is stopped - depends on how much memory it has to scan, not on how much memory has been allocated by the GC. In many cases, that's just the GC heap plus the stack, but if you're malloc-ing memory, and that memory can hold references to GC-allocated memory, then you have to tell the GC to scan that memory too in order to avoid having anything it references being prematurely collected. So, ultimately, how expensive the GC is in terms of performance generally depends on how much memory can hold referencs to GC-allocated objects and not how many such objects there are, meaning that avoiding allocating with the GC in a lot of your code doesn't necessarily save you from the performance cost of the GC. To avoid that cost, you'd need to either not have many places in malloc-ed memory which could refer to GC-allocated memory, or you'd need to write your code in a way that the it was guaranteed that the GC-allocated objects that were referenced in malloc-ed memory would have other references in memory that was scanned that lived longer htan the malloc-ed memory so that the malloc-ed memory wouldn't need to be scanned (which is quite possible in some circumstances but potentially risky).
>
> Using a 64-bit system significantly reduces the risk of false
> pointers, but it doesn't reduce the amount of memory that actually needs to be scanned. And whether using the GC for long-lived allocations and RC for short-lived ones would help would depend primarily on how many such objects would be around at any one time - and of course, whether they refer to GC-allocated memory and would thus need to be scanned. But reducing the amount of memory that the GC needs to scan and reduce how much is GC-allocated are two separate - albeit related - problems.
>
> - Jonathan M Davis
Thanks you for the clear explanation. So if you don't have GC allocations within RC structures and pick one or the other, then the concern does not apply?
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Shachar Shemesh | On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh wrote: > On 13/09/16 02:21, deadalnix wrote: >> >> RC itself is not panacea, it doesn't work well with exceptions, generate >> a huge amount of code bloat, > > I will need explanation to those two. Assuming we have RAII, why doesn't RC work well with exceptions? > With RC, the runtime needs to resume every frames. That makes exception very slow. Plus you need to generate a bunch of unwinding code + LSDA infos, and it clusters like crazy when you have destructor that can throw. This is why ObjC exeption handling and ARC never worked well together. This is why C++ exception are dog slow and this is why Swift is nothrow by default. >> But first and foremost, it is a disaster for shared data. > > Again, please elaborate. > For shared data, you need synchronized reference counting, which is prohibitively expensive. > Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. > > Shachar No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach. |
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On 9/13/16 2:24 PM, deadalnix wrote:
> This is why ObjC exeption handling and ARC never worked well together.
> This is why C++ exception are dog slow and this is why Swift is nothrow
> by default.
Swift doesn't support exceptions AFAIK. It supports weird error handling that looks similar to exceptions, but is really just a standard return.
i.e. this:
do
{
try someFunctionThatErrors(arg)
}
catch(Exception ex)
{
// handle ex
}
really compiles like this:
var _err : Error?
someFunctionThatErrors(arg, &_err)
if(_err != nil)
{
let ex = _err!.exception
}
-Steve
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis wrote:
>
> As I understand it, [snnip]
If you ever write a book, I would pre-order it.
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Laeeth Isharc | Am Tue, 13 Sep 2016 18:16:27 +0000 schrieb Laeeth Isharc <laeethnospam@nospamlaeeth.com>: > Thanks you for the clear explanation. So if you don't have GC allocations within RC structures and pick one or the other, then the concern does not apply? That's right. Often such structures contain collections of things, not just plain fields. And a list or a hash map working in a @nogc environment typically checks its contained type for any pointers with hasIndirections!T and if so adds its storage area to the GC scanned memory to be on the safe side. That means every collection needs a way to exempt its contents from GC scanning and the user needs to remember to tell it so. A practical example of that are the EMSI containers, but other containers, i.e. in my own private code look similar. https://github.com/economicmodeling/containers struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange!T) { ... } Here, when you use a dynamic array you need to specify the type and allocator before you get to the point of opting out of GC scanning. Many will prefer concise code, go with GC scanning to be "better safe than sorry" or don't want to fiddle with the options as long as the program works. This is no complaint, I'm just trying to draw a picture of how people end up with more GC scanned memory than necessary. :) -- Marco |
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Tuesday, September 13, 2016 18:50:20 jmh530 via Digitalmars-d wrote:
> On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis
>
> wrote:
> > As I understand it, [snnip]
>
> If you ever write a book, I would pre-order it.
LOL. It's on my unfinished projects list, so I intend to complete it at some point, but unfortunately, it's been on the backburner for a while. Still, it's funny that you say that considering how many typos were in that post, since I neglected to reread it before sending it. :)
- Jonathan M Davis
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 9/13/2016 10:44 AM, Jonathan M Davis via Digitalmars-d wrote:
> Folks have posted here before about taking that approach with games and the
> like that they've written. In a number cases, simply being careful about
> specific pieces of code and avoiding the GC in those cases was enough to get
> the required performance. In some cases, simply disabling the GC during a
> critical piece of code and re-enabling it afterwards fixes the performance
> problems trigged by the GC without even needing manual memory management or
> RC. In others, making sure that the critical thread (e.g. the rendering
> thread) was not GC-managed while letting the rest of the app us the GC
> takes care of the problem.
>
> We need reference counting to solve certain problems (e.g. cases where
> deterministic destruction of stuff on the heap is required), but other stuff
> (like array slices) work far better with a GC. So going either full-on RC or
> full-on GC is not going to be good move for most programs. I don't think
> that there's any question that we'll be best off by having both as solid
> options, and best practices can develop as to when to use one or the other.
Case in point, exceptions. Currently exceptions are fairly wedded to being GC allocated. Some people have opined that this is a major problem, and it is if the app is throwing a lot of exceptions. But exceptions should be exceptional.
There is still a place for GC, even in a high performance app. The all-or-nothing approach to using the GC is as wrong as any programming methodology is.
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Tuesday, 13 September 2016 at 20:19:40 UTC, Jonathan M Davis wrote:
>
> LOL. It's on my unfinished projects list, so I intend to complete it at some point, but unfortunately, it's been on the backburner for a while. Still, it's funny that you say that considering how many typos were in that post, since I neglected to reread it before sending it. :)
>
> - Jonathan M Davis
Typos are for spellcheckers.
|
September 13, 2016 Re: iPhone vs Android | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Tuesday, September 13, 2016 14:43:09 Walter Bright via Digitalmars-d wrote:
> Case in point, exceptions. Currently exceptions are fairly wedded to being GC allocated. Some people have opined that this is a major problem, and it is if the app is throwing a lot of exceptions. But exceptions should be exceptional.
>
> There is still a place for GC, even in a high performance app. The all-or-nothing approach to using the GC is as wrong as any programming methodology is.
The big problem with exceptions being allocated by the GC isn't really the GC but @nogc. Obviously, a program that does not use the GC at all can't allocate an exception with the GC, but in general, I would fully expect that even a program that allows the GC but uses it minimally would have no problem with the garbage created by exceptions precisely because they should be rare. But none of the code that's marked @nogc can throw an exception unless you're either dealing with pre-allocated exceptions (in which case, they're less informative), or you are _very_ careful with how you write that code so that you can get away with malloc-ing the exception (but that approach won't work in the general case unless you don't care about leaking the memory from the exception, since most code would assume that the exception was allocated by the GC and wouldn't know how to free it). So, @nogc code is going to have a tendency to not use exceptions just because exceptions don't work well without the GC. And those who want to use exceptions and are willing to have their code not be @nogc will forgo @nogc even when the code could have been @nogc otherwise.
So, I really think that we need to find a way to make it so that exceptions aren't GC allocated normally anymore - or at least have a way to reasonably and easily not be GC allocated - but the problem is @nogc, not the actual memory management or its cost.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation