При получении подстроки в .Net, ссылается ли новая строка на те же данные исходной строки, или данные копируются?

Скорее всего, обе таблицы имеют столбец с тем же именем. Псевдоним каждой таблицы и вызовите каждый столбец с псевдонимом таблицы.

13
задан Elan 18 March 2010 в 22:36
поделиться

9 ответов

Это новая строка.

Строки в .NET всегда неизменяемы. Каждый раз, когда вы генерируете новую строку с помощью метода, включая Substring, он создает новую строку в памяти. Единственный раз, когда вы делитесь ссылками на одни и те же данные в строках в .NET, - это если вы явно назначаете строковую переменную другой строке (в которой она копирует ссылку) или если вы работаете со строковыми константами, которые обычно интернированы. Если вы знаете, что ваша строка будет разделять значение с интернированной строкой (константа / литерал из вашего кода), вы можете получить «общую» копию через String.Intern .

Это хорошо, кстати - для того, чтобы сделать то, что вы описывали, каждая строка потребовала бы ссылки (на строковые данные), а также смещения + длины. Прямо сейчас им требуется только ссылка на строковые данные.

Это резко увеличит размер строк в целом во фреймворке.

15
ответ дан 1 December 2019 в 18:55
поделиться

Создается новая строка, но это очень умный вопрос, который не исключен. Однако я думаю, что потеря производительности в большинстве случаев намного перевесит экономию памяти в редких случаях.

Недавно я услышал о чем-то, называемом «веревки», которые работали бы так, как вы предлагаете, но я не знаю ни одной реализации в .NET.

http://en.wikipedia.org/wiki/Rope_ (computer_science)

3
ответ дан 1 December 2019 в 18:55
поделиться

как сказал Рид, строки неизменяемы. если вы имеете дело с длинными строками, подумайте об использовании StringBuilder, это может улучшить производительность, конечно, в зависимости от того, чего вы пытаетесь достичь. если вы можете добавить некоторые детали к своему вопросу, вы обязательно получите предложение по лучшей реализации.

0
ответ дан 1 December 2019 в 18:55
поделиться

В CLR строки неизменяемы, что означает, что они не могут быть изменены. Когда манипулируя большими строками, я бы посоветовал взглянуть на использование класса построителя строк.

0
ответ дан 1 December 2019 в 18:55
поделиться

Как отмечали другие, среда CLR создает копии при выполнении операции с подстрокой.

Как вы заметили, строку, безусловно, можно было бы представить как внутренний указатель с длиной. Это делает операцию подстроки чрезвычайно дешевой.

Есть также способы удешевить другие операции. Например, конкатенацию строк можно удешевить, представив строки в виде дерева подстрок.

В обоих случаях то, что здесь происходит, является результатом операции, на самом деле не самим «результатом», а скорее дешевым объектом, который представляет возможность получить результаты, когда это необходимо.

Внимательный читатель только что понял, что именно так работает LINQ. Когда мы говорим

var results = from c in customers where c.City == "London" select c.Name;

«результаты», не содержит результаты запроса. Этот код возвращается почти сразу; results содержит объект, который представляет запрос . Только когда запрос повторяется, запускается дорогостоящий механизм поиска в коллекции. Мы используем мощь монадического представления семантики последовательности, чтобы отложить вычисления на потом.

Тогда возникает вопрос: «А можно ли проделать то же самое со строками?» и ответ - решительное «нет». У меня есть множество болезненных экспериментов по этому поводу в реальном мире. Однажды я провел лето, переписывая процедуры обработки строк компилятора VBScript для хранения конкатенации строк в виде дерева операций конкатенации строк; только когда результат фактически используется как строка, действительно происходит конкатенация.Это было ужасно; дополнительное время и память, необходимые для отслеживания всех строковых указателей, составляют 99% случай - кто-то выполняет несколько простых небольших строковых операций для рендеринга веб-страницы - примерно в два раза медленнее, при этом значительно ускоряя крошечное меньшинство страниц, написанных с использованием простых конкатенаций строк.

Подавляющее большинство реалистичных строковых операций в программах .NET выполняются чрезвычайно быстро; они компилируются в движения памяти, которые в нормальных условиях остаются в блоках памяти, которые кэшируются процессором, и поэтому работают невероятно быстро.

Кроме того, использование подхода «внутреннего указателя» для строк значительно усложняет сборщик мусора; использование такого подхода, похоже, увеличивает вероятность того, что сборщик мусора в целом замедлится, что никому не идет на пользу. Вы должны смотреть на общую стоимость воздействия изменения, а не только на его влияние на некоторые узкие сценарии.

Если у вас есть особые потребности в производительности из-за необычно большого объема данных, вам следует подумать о написании собственной специализированной строковой библиотеки, которая использует «монадический» подход, такой как LINQ. Вы можете представить свои строки внутри как массивы символов, и тогда операции с подстроками просто станут копированием ссылки на массив и изменением начальной и конечной позиций.

20
ответ дан 1 December 2019 в 18:55
поделиться

Строки неизменяемы, поэтому будет создана копия строки. Однако если подстрока совпадает с точной строкой другой строки, которая была известна во время компиляции, она будет использовать ту же память, что и эта подстрока. Это интернирование строк.

From MSDN: "Время выполнения общего языка автоматически поддерживает таблицу, называемую "пулом интернов", которая содержит один экземпляр каждой уникальной литеральной строковой константы, объявленной в программе, а также любой уникальный экземпляр String, который вы добавляете программно".

Пул интернов позволяет экономить место для хранения строк. Если вы присваиваете литеральную строковую константу нескольким переменным, каждая переменная будет ссылаться на одну и ту же константу в пуле intern вместо того, чтобы ссылаться на несколько различных экземпляров String, имеющих одинаковые значения."

Пример кода информативен. Вы можете предотвратить автоматическое интернирование, используя [assembly: CompilationRelaxations(CompilationRelaxations.NoStringInterning)] атрибута для предотвращения автоматического интернирования строк. Вам также придется использовать NGEN.exe для компиляции в родной образ, чтобы предотвратить интернирование.

Обратите внимание, что если вы используете StringBuilder, это позволяет избежать интернирования. Это только для строк, которые могут быть сопоставлены с другими строками, известными во время компиляции.

Это модифицированный пример из статьи MSDN, обратите внимание, что если я передаю часть "abcd" из консоли, она все равно интернируется, несмотря на то, что str3 строится во время выполнения. Однако StringBuilder избегает интернирования.

// Sample for String.IsInterned(String)
using System;
using System.Text;
using System.Runtime.CompilerServices;
using System.Diagnostics;

// In the .NET Framework 2.0 the following attribute declaration allows you to 
// avoid the use of the interning when you use NGEN.exe to compile an assembly 
// to the native image cache.
//[assembly: CompilationRelaxations(CompilationRelaxations.NoStringInterning)]
class Sample
{
    public static void Main()
    {
        // String str1 is known at compile time, and is automatically interned.
        String str1 = "abcd";
        Console.WriteLine("Type cd and it will be ok, type anything else and Assert will fail.");
        string end = Console.ReadLine(); // Constructed, but still interned.
        string str3 = "ab" + end;

        // Constructed string, str2, is not explicitly or automatically interned.
        String str2 = new StringBuilder().Append("wx").Append("yz").ToString();
        Console.WriteLine();
        Test(1, str1);
        Test(2, str2);
        Test(3, str3);

        // Sanity checks. 
        // Debug.Assert(Object.ReferenceEquals(str3, str1)); // Assertion fails, as expected.
         Debug.Assert(Object.ReferenceEquals(string.Intern(str3), string.Intern(str1))); // Passes
         Debug.Assert(Object.ReferenceEquals(string.Intern(str3), (str1))); // Passes
         Debug.Assert(Object.ReferenceEquals((str3), string.Intern(str1))); // Fails
         Console.ReadKey();
    }

    public static void Test(int sequence, String str)
    {
        Console.Write("{0}) The string, '", sequence);
        String strInterned = String.IsInterned(str);
        if (strInterned == null)
            Console.WriteLine("{0}', is not interned.", str);
        else
            Console.WriteLine("{0}', is interned.", strInterned);
    }
}
0
ответ дан 1 December 2019 в 18:55
поделиться

Знаешь что, я ничего не знаю о .NET.

Но я хотел бы сделать одно наблюдение.

Большинство современных пакетов String имеют поведение «копирование при записи».

В частности, это означает, что если вы выделяете подстроку, она будет использовать существующее хранилище родительской строки до тех пор, пока строка не будет нуждаться в изменении, после чего она скопирует базовые данные в свое собственное новое пространство для использовать.

Теперь, если у вас есть неизменяемые строки, в которых базовые данные не могут измениться, нет особых причин НЕ делать этого. Невозможно «записать» в неизменяемую строку, поэтому для нее даже не нужно копировать функции записи, а просто делиться. В C ++ есть изменяемые строки, поэтому они копируются при записи.

Например, это делает Java.

Обычно это хорошо. Небольшое влияние на производительность.

Однако вы НЕ хотите, чтобы это происходило, в следующем примере:

String big1MBString = readLongHonkinStringFromTheInterTubes();
static String ittyBitty = big1MBString.substring(1, 5);

Теперь у вас есть строка из 5 символов, которая занимает 1 МБ памяти, потому что она разделяет нижележащий строковый буфер размером 1 МБ для большого строка, но это всего лишь строка из 5 символов. Поскольку вы сохраняете внутреннюю ссылку на более крупную строку, вы «никогда» не освободите исходное пространство.

Если посмотреть на исходники Mono, они действительно выделяют новую память. Так что, возможно, .NET является исключением из того, что сегодня кажется обычной практикой. Несомненно, у них есть свои веские и обоснованные причины (т.е. я не говорю, что .NET сделал это неправильно), просто ... отличные от того, что делают другие.

1
ответ дан 1 December 2019 в 18:55
поделиться

Он ссылается на новую строку.

1
ответ дан 1 December 2019 в 18:55
поделиться

Подстрока создает новую строку. Таким образом, будет выделена новая память для новой строки.

0
ответ дан 1 December 2019 в 18:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: