2016-05-04 5 views
1
package main 

import (
    "fmt" 
    "unsafe" 
    "runtime" 
) 

func getPoi() unsafe.Pointer { 
    var a = []int{1, 2, 3} 
    return unsafe.Pointer(&a[0]) 
} 

func main() { 
    p := getPoi() 
    runtime.GC() 
    fmt.Println("Hello, playground %v\n", *(*int)(unsafe.Pointer(uintptr(p)+8))) 
} 

выход: 3Безопасно ли удерживать только небезопасное. Заходите на первый элемент среза и нет ссылок на этот фрагмент?

https://play.golang.org/p/-OQl7KeL9a

Просто исследующие способности небезопасных указателей, пытаясь свести к минимуму накладных расходов памяти структуры среза (12 байт)

Интересно, если этому пример правильно или нет. И если нет, то что будет не так точно после таких действий. если это неверно, почему значение все еще доступно даже после явного вызова GC? Есть ли какой-либо aproach для достижения минимальных накладных расходов при хранении, таких как «кусочек срезов», как это было бы в C (просто массив указателей на выделенные массивы, когда накладные расходы для каждой строки - sizeof (int *)).

+0

Возможно, вам лучше сократить потребление памяти с помощью int32 или даже int16, чем сэкономить 2 * 8 байт, заменив заголовок среза небезопасным.Pointer. Для случая среза кусочка среза: сделайте один срез и сделайте сам расчет индекса (см., Например, изображение пакета). – Volker

+0

Также имейте в виду, что int составляет 4 байта на 32-битных системах и 8 байтах на 64-битной, поэтому, если вы собираетесь использовать указатели, убедитесь, что вы используете размер int. Кроме того, если производительность срезов действительно важна, используйте Go from git (или подождите 1.7), произошли значительные улучшения производительности. – OneOfOne

+0

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

ответ

0

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

Кроме того, как правило, я вижу, как люди делают всевозможные глупые вещи, чтобы попытаться повысить производительность, когда их дизайн по своей сути беден (например, с использованием динамических массивов или связанных списков без причины). Если вам нужен динамический рост среза, то массив на самом деле не является вариантом (и использование этого указателя также, скорее всего, небезопасно), но во многих случаях разработчики просто не могут правильно сортировать свою коллекцию из idk, лень? Я предполагаю, что ваш пример надуман, но в таком случае у вас нет причин когда-либо использовать срез, так как размер ваших коллекций известен во время компиляции. Даже если бы это было не так, часто раз размер можно определить во время выполнения перед распределением, и люди просто не могут сделать это для удобства использования абстрактных коллекций с динамическим размером.

+0

Кстати, я думаю, массив - хороший вариант, потому что, если сравнивать с некоторыми списками (что позволяет легко расти без повторного использования), это дает наилучшее использование памяти и производительность сканирования. Я думаю, это очень конкретный вопрос, какую коллекцию использовать, в зависимости от конкретных условий. – Exel

+0

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